//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: ShaderAPIDx11 implementation // // $NoKeywords: $ // //===========================================================================// // HUH??? #define RAD_TELEMETRY_DISABLED #include "shaderapidx11.h" #include "shaderapidx9/shaderapibase.h" #include "shaderapi/ishaderutil.h" #include "shaderapi/commandbuffer.h" #include "materialsystem/idebugtextureinfo.h" #include "materialsystem/materialsystem_config.h" #include "materialsystem/imorph.h" #include "meshdx11.h" #include "shadershadowdx11.h" #include "shaderdevicedx11.h" #include "shaderapidx11_global.h" #include "imaterialinternal.h" #include "ShaderConstantBufferDx11.h" #include "vertexshaderdx11.h" #include "VertexBufferDx11.h" #include "IndexBufferDx11.h" #include "materialsystem/IShader.h" #include "../stdshaders/cpp_shader_constant_register_map.h" #include "Dx11Global.h" #include "ITextureInternal.h" // NOTE: This has to be the last file included! #include "tier0/memdbgon.h" template FORCEINLINE static void XMSetComponent4( T &vec, int comp, float val ) { switch ( comp ) { case 0: vec.x = val; break; case 1: vec.y = val; break; case 2: vec.z = val; break; case 3: vec.w = val; break; } } //------------------------------------------------------------------- // Common constant buffers, grouped by frequency of update. // NOTE: These need to match the cbuffers in common_cbuffers_fxc.h!!! //------------------------------------------------------------------- // In order of most frequent to least frequent... // NOTE: ShaderAPI is not responsible for constant buffers // that change every material/draw call/shader, but the shader // class itself. ALIGN16 struct DX11LightInfo_t { DirectX::XMFLOAT4 color; DirectX::XMFLOAT4 dir; DirectX::XMFLOAT4 pos; DirectX::XMFLOAT4 spotParams; DirectX::XMFLOAT4 atten; }; // Constants that can be expected to change for each model. ALIGN16 struct PerModel_CBuffer_t { DirectX::XMMATRIX cModelMatrix; // If using skinning, same as cModel[0] // Four lights x 5 constants each = 20 constants DX11LightInfo_t cLightInfo[4]; DirectX::XMINT4 cLightCount; DirectX::XMFLOAT3A cAmbientCube[6]; }; // These were split from per-model because they are big ALIGN16 struct Skinning_CBuffer_t { DirectX::XMFLOAT3X4A cModel[53]; }; ALIGN16 struct Flex_CBuffer_t { DirectX::XMFLOAT4 cFlexWeights[512]; }; // Constants that can be expected to change each frame. // TODO: Can we save a constant by having the vertex shader // extract the eye position from the viewmatrix? ALIGN16 struct PerFrame_CBuffer_t { DirectX::XMMATRIX cViewMatrix; DirectX::XMFLOAT4 cEyePos; DirectX::XMFLOAT4 cTonemappingScale; DirectX::XMFLOAT4 cFlashlightPos; }; // Constants that don't change per-material, per-model, or per-frame. // These are expected to be changed whenever and apply to all materials. // TODO: Figure out how often these flashlight parameters change, // particularly cFlashlightWorldToTexture. ALIGN16 struct PerScene_CBuffer_t { DirectX::XMMATRIX cProjMatrix; DirectX::XMMATRIX cFlashlightWorldToTexture; DirectX::XMFLOAT4 cFlashlightScreenScale; DirectX::XMFLOAT4 cFlashlightColor; DirectX::XMFLOAT4 cFlashlightAttenuationFactors; DirectX::XMFLOAT4 cShadowTweaks; DirectX::XMFLOAT4 cConstants; // Only cFlexScale.x is used // It is a binary value used to switch on/off the addition of the flex delta stream DirectX::XMFLOAT4 cFlexScale; // NOTE: Fog has moved to per-material constants, defined and requested by each shader. }; enum { MATRIXDX11_DIRTY, MATRIXDX11_IDENTITY, }; //----------------------------------------------------------------------------- // // Shader API Dx11 // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Class Factory //----------------------------------------------------------------------------- static CShaderAPIDx11 s_ShaderAPIDx11; CShaderAPIDx11 *g_pShaderAPIDx11 = &s_ShaderAPIDx11; EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx11, IShaderAPI, SHADERAPI_INTERFACE_VERSION, s_ShaderAPIDx11 ) EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx11, IDebugTextureInfo, DEBUG_TEXTURE_INFO_VERSION, s_ShaderAPIDx11 ) //----------------------------------------------------------------------------- // Constructor, destructor //----------------------------------------------------------------------------- CShaderAPIDx11::CShaderAPIDx11() : m_Textures( 32 ), m_SelectionMinZ( FLT_MAX ), m_SelectionMaxZ( FLT_MIN ), m_pSelectionBuffer( 0 ), m_pSelectionBufferEnd( 0 ), m_nDynamicVBSize( DYNAMIC_VERTEX_BUFFER_MEMORY ), m_TexAnisotropy( 0 ) { m_ModifyTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE; m_ModifyTextureLockedLevel = -1; m_ModifyTextureLockedFace = -1; m_bResettingRenderState = false; m_ShadowState = NULL; m_ShaderState = StatesDx11::ShaderState(); m_DynamicState = StatesDx11::DynamicState(); m_StateChangeFlags = STATE_CHANGED_NONE; m_bSelectionMode = false; m_bFlashlightStateChanged = false; m_pFlashlightDepthTexture = NULL; m_CurrentSnapshot = DEFAULT_SHADOW_STATE_ID; memset( IntRenderingParameters, 0, sizeof( IntRenderingParameters ) ); memset( FloatRenderingParameters, 0, sizeof( FloatRenderingParameters ) ); memset( VectorRenderingParameters, 0, sizeof( VectorRenderingParameters ) ); } CShaderAPIDx11::~CShaderAPIDx11() { } void CShaderAPIDx11::UpdateConstantBuffer( ConstantBufferHandle_t cbuffer, void *pNewData ) { g_pShaderDeviceDx11->UpdateConstantBuffer( cbuffer, pNewData ); } ConstantBufferHandle_t CShaderAPIDx11::GetInternalConstantBuffer( int type ) { switch ( type ) { case SHADER_CONSTANTBUFFER_PERFRAME: return m_hPerFrameConstants; case SHADER_CONSTANTBUFFER_PERMODEL: return m_hPerModelConstants; case SHADER_CONSTANTBUFFER_PERSCENE: return m_hPerSceneConstants; case SHADER_CONSTANTBUFFER_SKINNING: return m_hSkinningConstants; //case SHADER_CONSTANTBUFFER_FLEX: // return m_hFlexConstants; default: return CONSTANT_BUFFER_HANDLE_INVALID; } } //----------------------------------------------------------------------------- // Resets the render state //----------------------------------------------------------------------------- void CShaderAPIDx11::ResetRenderState( bool bFullReset ) { m_StateChangeFlags = STATE_CHANGED_NONE; m_ShadowState = NULL; m_CurrentSnapshot = DEFAULT_SHADOW_STATE_ID; m_DynamicState.Reset(); m_DynamicState.m_pDepthStencilView = GetTexture( m_hDepthBuffer ).GetDepthStencilView(); m_ShaderState.SetDefault(); m_pCurMatrixItem = &m_ShaderState.m_MatrixStacks[0].Top(); IssueStateChanges( bFullReset ); } void CShaderAPIDx11::SetRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t colorTextureHandle, ShaderAPITextureHandle_t depthTextureHandle ) { // GR - need to flush batched geometry FlushBufferedPrimitives(); if ( colorTextureHandle == SHADER_RENDERTARGET_BACKBUFFER ) { colorTextureHandle = m_hBackBuffer; } else if ( colorTextureHandle == SHADER_RENDERTARGET_NONE ) { colorTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE; } if ( depthTextureHandle == SHADER_RENDERTARGET_DEPTHBUFFER ) { depthTextureHandle = m_hDepthBuffer; } else if ( depthTextureHandle == SHADER_RENDERTARGET_NONE ) { depthTextureHandle = INVALID_SHADERAPI_TEXTURE_HANDLE; } if ( colorTextureHandle != INVALID_SHADERAPI_TEXTURE_HANDLE ) { CTextureDx11 *pRT = &GetTexture( colorTextureHandle ); m_DynamicState.m_pRenderTargetViews[nRenderTargetID] = pRT->GetRenderTargetView(); SetStateFlag( STATE_CHANGED_RENDERTARGET ); } else { m_DynamicState.m_pRenderTargetViews[nRenderTargetID] = NULL; } if ( depthTextureHandle != INVALID_SHADERAPI_TEXTURE_HANDLE ) { CTextureDx11 *pDT = &GetTexture( depthTextureHandle ); m_DynamicState.m_pDepthStencilView = pDT->GetDepthStencilView(); SetStateFlag( STATE_CHANGED_DEPTHBUFFER ); } else { m_DynamicState.m_pDepthStencilView = NULL; } } //----------------------------------------------------------------------------- // Issues state changes to D3D for states that have been modified //----------------------------------------------------------------------------- void CShaderAPIDx11::IssueStateChanges( bool bForce ) { // Don't bother committing anything if we're deactivated if ( g_pShaderDeviceDx11->IsDeactivated() ) return; m_ShadowState = g_pShaderShadowDx11->GetShadowState( m_CurrentSnapshot ); //const StatesDx11::ShadowState *shadow = m_ShadowState; StatesDx11::DynamicState &dynamic = m_DynamicState; DoIssueShaderState( bForce ); if ( bForce || IsStateSet( STATE_CHANGED_RENDERTARGET ) || IsStateSet( STATE_CHANGED_DEPTHBUFFER ) ) { DoIssueRenderTargets(); } if ( bForce || IsStateSet( STATE_CHANGED_VIEWPORTS ) ) { DoIssueViewports(); } if ( bForce || IsStateSet( STATE_CHANGED_INPUTLAYOUT ) ) { DoIssueInputLayout(); } if ( bForce || IsStateSet( STATE_CHANGED_VERTEXBUFFER ) ) { DoIssueVertexBuffer(); } if ( bForce || IsStateSet( STATE_CHANGED_INDEXBUFFER ) ) { DoIssueIndexBuffer(); } if ( bForce || IsStateSet( STATE_CHANGED_TOPOLOGY ) ) { DoIssueTopology(); } if ( bForce || IsStateSet( STATE_CHANGED_VERTEXSHADER ) ) { DoIssueVertexShader(); } if ( bForce || IsStateSet( STATE_CHANGED_GEOMETRYSHADER ) ) { DoIssueGeometryShader(); } if ( bForce || IsStateSet( STATE_CHANGED_PIXELSHADER ) ) { DoIssuePixelShader(); } DoIssueConstantBuffers( bForce ); bool bPixel = bForce || IsStateSet( STATE_CHANGED_SAMPLERS ); bool bVertex = bForce || IsStateSet( STATE_CHANGED_VERTEXSAMPLERS ); if ( bPixel || bVertex ) { DoIssueSampler( bPixel, bVertex ); dynamic.m_PrevMaxPSSampler = dynamic.m_MaxPSSampler; dynamic.m_PrevMaxVSSampler = dynamic.m_MaxVSSampler; } bPixel = bForce || IsStateSet( STATE_CHANGED_TEXTURES ); bVertex = bForce || IsStateSet( STATE_CHANGED_VERTEXTEXTURES ); if ( bPixel || bVertex ) { DoIssueTexture( bPixel, bVertex ); } if ( bForce || IsStateSet( STATE_CHANGED_DEPTHSTENCIL ) ) { DoIssueDepthStencilState(); } if ( bForce || IsStateSet( STATE_CHANGED_BLEND ) ) { DoIssueBlendState(); } if ( bForce || IsStateSet( STATE_CHANGED_RASTERIZER ) ) { DoIssueRasterState(); } m_StateChangeFlags = STATE_CHANGED_NONE; m_ShadowState = NULL; } //------------------------------ // Issue state changes //------------------------------ FORCEINLINE static void OutputMatrixRow( const DirectX::XMFLOAT4X4 &mat, int r ) { Log( "\t%f\t%f\t%f\t%f\n", mat.m[r][0], mat.m[r][1], mat.m[r][2], mat.m[r][3] ); } FORCEINLINE static void OutputMatrix( const DirectX::XMFLOAT4X4 &mat, const char *pszMatName ) { Log( "DX11 %s Matrix:\n", pszMatName ); for ( int i = 0; i < 4; i++ ) { OutputMatrixRow( mat, i ); } } int CShaderAPIDx11::ComputeNumLights() const { int numLights = 0; for ( int i = 0; i < MAX_NUM_LIGHTS; i++ ) { if ( m_ShaderState.light.m_Lights[i].m_Type != MATERIAL_LIGHT_DISABLE ) numLights++; } return numLights; } void CShaderAPIDx11::SortLights( int *index ) { m_ShaderState.light.m_NumLights = 0; for ( int i = 0; i < MAX_NUM_LIGHTS; i++ ) { const LightDesc_t &light = m_ShaderState.light.m_Lights[i]; LightType_t type = light.m_Type; int j = m_ShaderState.light.m_NumLights; if ( type != MATERIAL_LIGHT_DISABLE ) { while ( --j >= 0 ) { if ( m_ShaderState.light.m_LightType[j] <= type ) break; // shift... m_ShaderState.light.m_LightType[j + 1] = m_ShaderState.light.m_LightType[j]; if ( index ) index[j + 1] = index[j]; } ++j; m_ShaderState.light.m_LightType[j] = type; if ( index ) index[j] = i; ++m_ShaderState.light.m_NumLights; } } } FORCEINLINE static float ShadowAttenFromState( FlashlightState_t const &state ) { // DX10 requires some hackery due to sRGB/blend ordering change from DX9, which makes the shadows too light if ( g_pHardwareConfig->UsesSRGBCorrectBlending() ) return state.m_flShadowAtten * 0.1f; // magic number return state.m_flShadowAtten; } FORCEINLINE static float ShadowFilterFromState( FlashlightState_t const &state ) { return state.m_flShadowFilterSize / state.m_flShadowMapResolution; } FORCEINLINE static void HashShadow2DJitter( const float fJitterSeed, float *fU, float *fV ) { const int nTexRes = 32; int nSeed = fmod( fJitterSeed, 1.0f ) * nTexRes * nTexRes; int nRow = nSeed / nTexRes; int nCol = nSeed % nTexRes; // Div and mod to get an individual texel in the fTexRes x fTexRes grid *fU = nRow / (float)nTexRes; // Row *fV = nCol / (float)nTexRes; // Column } void CShaderAPIDx11::DoIssueShaderState( bool bForce ) { // // Transforms // bool bViewChanged = m_ShaderState.m_ChangedMatrices[MATERIAL_VIEW]; bool bProjChanged = m_ShaderState.m_ChangedMatrices[MATERIAL_PROJECTION]; bool bModelChanged = m_ShaderState.m_ChangedMatrices[MATERIAL_MODEL]; PerFrame_CBuffer_t *pPerFrameConstants; PerModel_CBuffer_t *pPerModelConstants; PerScene_CBuffer_t *pPerSceneConstants; //{ //VPROF_BUDGET( "GetCBufferPointers", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); // To avoid an extra memcmp + memcpy... pPerFrameConstants = (PerFrame_CBuffer_t *) ( (CShaderConstantBufferDx11 *)m_hPerFrameConstants )->GetData(); pPerModelConstants = (PerModel_CBuffer_t *) ( (CShaderConstantBufferDx11 *)m_hPerModelConstants )->GetData(); pPerSceneConstants = (PerScene_CBuffer_t *) ( (CShaderConstantBufferDx11 *)m_hPerSceneConstants )->GetData(); //} bool bPerFrameChanged = false; bool bPerModelChanged = false; bool bPerSceneChanged = false; if ( bForce || bViewChanged ) { //VPROF_BUDGET( "CShaderAPIDx11::IssueViewMatrix", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); #ifdef _DEBUG const DirectX::XMMATRIX view = GetMatrix( MATERIAL_VIEW ); #else const DirectX::XMMATRIX &view = GetMatrix( MATERIAL_VIEW ); #endif // Row-major -> column-major pPerFrameConstants->cViewMatrix = DirectX::XMMatrixTranspose( view ); // Store new view position. DirectX::XMFLOAT4X4 flt4x4view; DirectX::XMStoreFloat4x4( &flt4x4view, DirectX::XMMatrixInverse( NULL, view ) ); pPerFrameConstants->cEyePos.x = flt4x4view.m[3][0]; pPerFrameConstants->cEyePos.y = flt4x4view.m[3][1]; pPerFrameConstants->cEyePos.z = flt4x4view.m[3][2]; m_ShaderState.m_ChangedMatrices[MATERIAL_VIEW] = false; bPerFrameChanged = true; } if ( bForce || bModelChanged ) { //VPROF_BUDGET( "CShaderAPIDx11::IssueModelMatrix", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); #ifdef _DEBUG const DirectX::XMMATRIX model = GetMatrix( MATERIAL_MODEL ); #else const DirectX::XMMATRIX &model = GetMatrix( MATERIAL_MODEL ); #endif // Row-major -> column-major pPerModelConstants->cModelMatrix = DirectX::XMMatrixTranspose( model ); m_ShaderState.m_ChangedMatrices[MATERIAL_MODEL] = false; bPerModelChanged = true; } if ( bForce || bProjChanged ) { //VPROF_BUDGET( "CShaderAPIDx11::IssueProjMatrix", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); #ifdef _DEBUG const DirectX::XMMATRIX proj = GetMatrix( MATERIAL_PROJECTION ); #else const DirectX::XMMATRIX &proj = GetMatrix( MATERIAL_PROJECTION ); #endif // Row-major -> column-major pPerSceneConstants->cProjMatrix = DirectX::XMMatrixTranspose( proj ); m_ShaderState.m_ChangedMatrices[MATERIAL_PROJECTION] = false; bPerSceneChanged = true; } // // Lighting // if ( bForce || m_ShaderState.light.m_bLightChanged ) { //VPROF_BUDGET( "CShaderAPIDx11::IssueLightState", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); int lightIndex[MAX_NUM_LIGHTS]; memset( lightIndex, 0, sizeof( lightIndex ) ); SortLights( lightIndex ); pPerModelConstants->cLightCount.x = m_ShaderState.light.m_NumLights; //if ( m_ShaderState.light.m_NumLights == 0 ) //{ // memset( &pPerModelConstants->cLightEnabled, 0, sizeof( DirectX::XMINT4 ) ); //} for ( int i = 0; i < m_ShaderState.light.m_NumLights; i++ ) { const LightDesc_t &light = m_ShaderState.light.m_Lights[lightIndex[i]]; //XMSetComponent4( pPerModelConstants->cLightEnabled, i, light.m_Type != MATERIAL_LIGHT_DISABLE ); // The first one is the light color ( and light type code ) float w = ( light.m_Type == MATERIAL_LIGHT_DIRECTIONAL ) ? 1.0f : 0.0f; pPerModelConstants->cLightInfo[i].color = DirectX::XMFLOAT4( light.m_Color.x, light.m_Color.y, light.m_Color.z, w ); // The next constant holds the light direction ( and light type code ) w = ( light.m_Type == MATERIAL_LIGHT_SPOT ) ? 1.0f : 0.0f; pPerModelConstants->cLightInfo[i].dir = DirectX::XMFLOAT4( light.m_Direction.x, light.m_Direction.y, light.m_Direction.z, w ); // The next constant holds the light position pPerModelConstants->cLightInfo[i].pos = DirectX::XMFLOAT4( light.m_Position.x, light.m_Position.y, light.m_Position.z, 1.0f ); // The next constant holds exponent, stopdot, stopdot2, 1 / (stopdot - stopdot2) if ( light.m_Type == MATERIAL_LIGHT_SPOT ) { float stopdot = cos( light.m_Theta * 0.5f ); float stopdot2 = cos( light.m_Phi * 0.5f ); float oodot = ( stopdot > stopdot2 ) ? 1.0f / ( stopdot - stopdot2 ) : 0.0f; pPerModelConstants->cLightInfo[i].spotParams = DirectX::XMFLOAT4( light.m_Falloff, stopdot, stopdot2, oodot ); } else { pPerModelConstants->cLightInfo[i].spotParams = DirectX::XMFLOAT4( 0, 1, 1, 1 ); } // The last constant holds atten0, atten1, atten2 pPerModelConstants->cLightInfo[i].atten = DirectX::XMFLOAT4( light.m_Attenuation0, light.m_Attenuation1, light.m_Attenuation2, 0.0f ); } m_ShaderState.light.m_bLightChanged = false; bPerModelChanged = true; } if ( bForce || m_ShaderState.light.m_bAmbientChanged ) { //VPROF_BUDGET( "CShaderAPIDx11::IssueAmbientState", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); memcpy( pPerModelConstants->cAmbientCube, m_ShaderState.light.m_AmbientLightCube, sizeof( DirectX::XMFLOAT3A ) * 6 ); m_ShaderState.light.m_bAmbientChanged = false; bPerModelChanged = true; } // // Skinning // if ( bForce || m_ShaderState.bone.m_bBonesChanged ) { //VPROF_BUDGET( "CShaderAPIDx11::IssueBoneState", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); // Since skinning is in it's own constant buffer and we are updating the whole // thing if bones have changed, be more efficient and lock the buffer to // avoid an extra memcpy. Skinning_CBuffer_t *pSkinningConstants = (Skinning_CBuffer_t *) ( (CShaderConstantBufferDx11 *)m_hSkinningConstants )->Lock(); // Load the model matrix from the matrix stack into the // first bone matrix. DirectX::XMMATRIX model = GetMatrix( MATERIAL_MODEL ); // This is stored row-major, needs to be column-major in shader. // 3x4 in DirectXMath becomes 4x3 in HLSL shader DirectX::XMStoreFloat3x4A( m_ShaderState.bone.m_BoneMatrix, model ); m_ShaderState.bone.m_MaxBoneLoaded++; int matricesLoaded = max( 1, m_ShaderState.bone.m_MaxBoneLoaded ); m_ShaderState.bone.m_MaxBoneLoaded = 0; // Copy bone matrices into cModel constant memcpy( pSkinningConstants->cModel, m_ShaderState.bone.m_BoneMatrix, sizeof( DirectX::XMFLOAT3X4A ) * matricesLoaded ); m_ShaderState.bone.m_bBonesChanged = false; ( (CShaderConstantBufferDx11 *)m_hSkinningConstants )->Unlock(); } // // Morphing // if ( bForce || m_ShaderState.morph.m_bMorphChanged ) { //VPROF_BUDGET( "CShaderAPIDx11::IssueMorphState", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); // Since flex is in it's own constant buffer and we are updating the whole // thing if flex has changed, be more efficient and lock the buffer to // avoid an extra memcpy. //Flex_CBuffer_t *pFlexConstants = (Flex_CBuffer_t *) // ( (CShaderConstantBufferDx11 *)m_hFlexConstants )->Lock(); //memcpy( pFlexConstants->cFlexWeights, m_ShaderState.morph.m_pWeights, // sizeof( MorphWeight_t ) * m_ShaderState.morph.m_nMaxWeightLoaded ); //m_ShaderState.morph.m_nMaxWeightLoaded = 0; //pPerModelConstants->cFlexScale = DirectX::XMFLOAT4( 0.0f, 0.0f, 0.0f, 0.0f ); //m_ShaderState.morph.m_bMorphChanged = false; //bPerModelChanged = true; //( (CShaderConstantBufferDx11 *)m_hFlexConstants )->Unlock(); } // // Flashlight // if ( m_bFlashlightStateChanged ) { //VPROF_BUDGET( "CShaderAPIDx11::IssueFlashLightState", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); float flFlashlightScale = 0.25f; if ( !g_pHardwareConfig->GetHDREnabled() ) { // Non-HDR path requires 2.0 flashlight flFlashlightScale = 2.0f; } // DX10 requires some hackery due to sRGB/blend ordering change from DX9 if ( g_pHardwareConfig->UsesSRGBCorrectBlending() ) { flFlashlightScale *= 2.5f; // Magic number that works well on the NVIDIA 8800 } float const *pFlashlightColor = m_FlashlightState.m_Color; float vPsConst[4] = { flFlashlightScale * pFlashlightColor[0], flFlashlightScale * pFlashlightColor[1], flFlashlightScale * pFlashlightColor[2], pFlashlightColor[3] }; vPsConst[3] = 0.0f; // This will be added to N.L before saturate to force a 1.0 N.L term pPerSceneConstants->cFlashlightColor = DirectX::XMFLOAT4( vPsConst ); DirectX::XMFLOAT4X4 flashlightWorldToTexture4x4 = DirectX::XMFLOAT4X4( m_FlashlightWorldToTexture.Base() ); pPerSceneConstants->cFlashlightWorldToTexture = DirectX::XMLoadFloat4x4( &flashlightWorldToTexture4x4 ); // Dimensions of screen, used for screen-space noise map sampling float vScreenScale[4] = { 1280.0f / 32.0f, 720.0f / 32.0f, 0, 0 }; int nWidth, nHeight; GetBackBufferDimensions( nWidth, nHeight ); vScreenScale[0] = (float)nWidth / 32.0f; vScreenScale[1] = (float)nHeight / 32.0f; pPerSceneConstants->cFlashlightScreenScale = DirectX::XMFLOAT4( vScreenScale ); // Tweaks associated with a given flashlight float tweaks[4]; tweaks[0] = m_FlashlightState.m_flShadowFilterSize / m_FlashlightState.m_flShadowMapResolution; tweaks[1] = ShadowAttenFromState( m_FlashlightState ); HashShadow2DJitter( m_FlashlightState.m_flShadowJitterSeed, &tweaks[2], &tweaks[3] ); pPerSceneConstants->cShadowTweaks = DirectX::XMFLOAT4( tweaks ); pPerFrameConstants->cFlashlightPos = DirectX::XMFLOAT4( m_FlashlightState.m_vecLightOrigin[0], m_FlashlightState.m_vecLightOrigin[1], m_FlashlightState.m_vecLightOrigin[2], 1.0f ); pPerSceneConstants->cFlashlightAttenuationFactors = DirectX::XMFLOAT4( m_FlashlightState.m_fConstantAtten, m_FlashlightState.m_fLinearAtten, m_FlashlightState.m_fQuadraticAtten, m_FlashlightState.m_FarZ ); bPerSceneChanged = true; bPerFrameChanged = true; m_bFlashlightStateChanged = false; } if ( bForce || m_ShaderState.m_bToneMappingScaleChanged ) { pPerFrameConstants->cTonemappingScale = DirectX::XMFLOAT4( m_ShaderState.m_ToneMappingScale.Base() ); m_ShaderState.m_bToneMappingScaleChanged = false; } //{ //VPROF_BUDGET( "ForceUpdate constants", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED ); // // Supply the new constants. // if ( bPerModelChanged ) ( (CShaderConstantBufferDx11 *)m_hPerModelConstants )->ForceUpdate(); if ( bPerFrameChanged ) ( (CShaderConstantBufferDx11 *)m_hPerFrameConstants )->ForceUpdate(); if ( bPerSceneChanged ) ( (CShaderConstantBufferDx11 *)m_hPerSceneConstants )->ForceUpdate(); //} } void CShaderAPIDx11::DoIssueVertexShader() { D3D11DeviceContext()->VSSetShader( m_DynamicState.m_pVertexShader, NULL, 0 ); } void CShaderAPIDx11::DoIssuePixelShader() { D3D11DeviceContext()->PSSetShader( m_DynamicState.m_pPixelShader, NULL, 0 ); } void CShaderAPIDx11::DoIssueGeometryShader() { D3D11DeviceContext()->GSSetShader( m_DynamicState.m_pGeometryShader, NULL, 0 ); } bool CShaderAPIDx11::DoIssueConstantBuffers( bool bForce ) { const StatesDx11::ShadowState *shadow = m_ShadowState; if ( bForce || IsStateSet( STATE_CHANGED_VSCONSTANTBUFFERS ) ) { D3D11DeviceContext()->VSSetConstantBuffers( 0, shadow->desc.vsConstantBuffers.m_MaxSlot + 1, shadow->desc.vsConstantBuffers.m_ppBuffers ); } if ( bForce || IsStateSet( STATE_CHANGED_GSCONSTANTBUFFERS ) ) { D3D11DeviceContext()->GSSetConstantBuffers( 0, shadow->desc.gsConstantBuffers.m_MaxSlot + 1, shadow->desc.gsConstantBuffers.m_ppBuffers ); } if ( bForce || IsStateSet( STATE_CHANGED_PSCONSTANTBUFFERS ) ) { D3D11DeviceContext()->PSSetConstantBuffers( 0, shadow->desc.psConstantBuffers.m_MaxSlot + 1, shadow->desc.psConstantBuffers.m_ppBuffers ); } return true; } void CShaderAPIDx11::DoIssueSampler( bool bPixel, bool bVertex ) { if ( bPixel ) { int nSamplers = m_DynamicState.m_MaxPSSampler + 1; D3D11DeviceContext()->PSSetSamplers( 0, nSamplers, m_DynamicState.m_ppSamplers ); } if ( bVertex ) { int nSamplers = m_DynamicState.m_MaxVSSampler + 1; D3D11DeviceContext()->VSSetSamplers( 0, nSamplers, m_DynamicState.m_ppVertexSamplers ); } } void CShaderAPIDx11::DoIssueTexture( bool bPixel, bool bVertex ) { if ( bPixel ) { int nSamplers = m_DynamicState.m_MaxPSSampler + 1; D3D11DeviceContext()->PSSetShaderResources( 0, nSamplers, m_DynamicState.m_ppTextures ); } if ( bVertex ) { int nSamplers = m_DynamicState.m_MaxVSSampler + 1; D3D11DeviceContext()->VSSetShaderResources( 0, nSamplers, m_DynamicState.m_ppVertexTextures ); } } void CShaderAPIDx11::DoIssueRasterState() { D3D11DeviceContext()->RSSetState( m_ShadowState->desc.rasterizer.m_pD3DState ); } void CShaderAPIDx11::DoIssueBlendState() { D3D11DeviceContext()->OMSetBlendState( m_ShadowState->desc.blend.m_pD3DState, m_ShadowState->desc.blend.BlendColor, m_ShadowState->desc.blend.SampleMask ); } void CShaderAPIDx11::DoIssueDepthStencilState() { D3D11DeviceContext()->OMSetDepthStencilState( m_ShadowState->desc.depthStencil.m_pD3DState, m_ShadowState->desc.depthStencil.StencilRef ); } bool CShaderAPIDx11::DoIssueVertexBuffer() { D3D11DeviceContext()->IASetVertexBuffers( 0, m_DynamicState.m_MaxVertexBuffer + 1, m_DynamicState.m_pVertexBuffer, m_DynamicState.m_pVBStrides, m_DynamicState.m_pVBOffsets ); m_DynamicState.m_PrevMaxVertexBuffer = m_DynamicState.m_MaxVertexBuffer; m_DynamicState.m_MaxVertexBuffer = -1; return true; } void CShaderAPIDx11::DoIssueIndexBuffer() { StatesDx11::DynamicState &dynamic = m_DynamicState; D3D11DeviceContext()->IASetIndexBuffer( dynamic.m_IndexBuffer.m_pBuffer, dynamic.m_IndexBuffer.m_Format, dynamic.m_IndexBuffer.m_nOffset ); } void CShaderAPIDx11::DoIssueInputLayout() { StatesDx11::DynamicState &dynamic = m_DynamicState; ID3D11InputLayout *pInputLayout = g_pShaderDeviceDx11->GetInputLayout( dynamic.m_InputLayout.m_hVertexShader, dynamic.m_InputLayout.m_pVertexDecl[0], dynamic.m_InputLayout.m_bStaticLit, dynamic.m_InputLayout.m_bUsingFlex, dynamic.m_InputLayout.m_bUsingMorph ); D3D11DeviceContext()->IASetInputLayout( pInputLayout ); } void CShaderAPIDx11::DoIssueTopology() { D3D11DeviceContext()->IASetPrimitiveTopology( m_DynamicState.m_Topology ); } void CShaderAPIDx11::DoIssueViewports() { D3D11DeviceContext()->RSSetViewports( m_DynamicState.m_nViewportCount, m_DynamicState.m_pViewports ); } void CShaderAPIDx11::DoIssueRenderTargets() { int nCount = 0; ID3D11RenderTargetView *rt; for ( ; nCount < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; nCount++ ) { rt = m_DynamicState.m_pRenderTargetViews[nCount]; if ( rt == NULL ) break; } if ( nCount > 0 ) { D3D11DeviceContext()->OMSetRenderTargets( nCount, m_DynamicState.m_pRenderTargetViews, NULL ); } else { // push the back buffer rt = GetTexture( m_hBackBuffer ).GetRenderTargetView(); D3D11DeviceContext()->OMSetRenderTargets( 1, &rt, m_DynamicState.m_pDepthStencilView ); } } //-------------------------------------------------------------------// //----------------------------------------------------------------------------- // Methods of IShaderDynamicAPI //----------------------------------------------------------------------------- void CShaderAPIDx11::GetBackBufferDimensions( int &nWidth, int &nHeight ) const { g_pShaderDeviceDx11->GetBackBufferDimensions( nWidth, nHeight ); } //----------------------------------------------------------------------------- // Viewport-related methods //----------------------------------------------------------------------------- void CShaderAPIDx11::SetViewports( int nCount, const ShaderViewport_t *pViewports ) { nCount = min( nCount, MAX_DX11_VIEWPORTS ); m_DynamicState.m_nViewportCount = nCount; for ( int i = 0; i < nCount; ++i ) { Assert( pViewports[i].m_nVersion == SHADER_VIEWPORT_VERSION ); D3D11_VIEWPORT &viewport = m_DynamicState.m_pViewports[i]; viewport.TopLeftX = pViewports[i].m_nTopLeftX; viewport.TopLeftY = pViewports[i].m_nTopLeftY; viewport.Width = pViewports[i].m_nWidth; viewport.Height = pViewports[i].m_nHeight; viewport.MinDepth = pViewports[i].m_flMinZ; viewport.MaxDepth = pViewports[i].m_flMaxZ; } SetStateFlag( STATE_CHANGED_VIEWPORTS ); } int CShaderAPIDx11::GetViewports( ShaderViewport_t *pViewports, int nMax ) const { int nCount = m_DynamicState.m_nViewportCount; if ( pViewports && nMax ) { nCount = min( nCount, nMax ); for ( int i = 0; i < nCount; i++ ) { const D3D11_VIEWPORT &vp = m_DynamicState.m_pViewports[i]; pViewports[i].m_nVersion = SHADER_VIEWPORT_VERSION; pViewports[i].m_nTopLeftX = vp.TopLeftX; pViewports[i].m_nTopLeftY = vp.TopLeftY; pViewports[i].m_nWidth = vp.Width; pViewports[i].m_nHeight = vp.Height; pViewports[i].m_flMaxZ = vp.MaxDepth; pViewports[i].m_flMinZ = vp.MinDepth; } } return nCount; } //----------------------------------------------------------------------------- // Methods related to clearing buffers //----------------------------------------------------------------------------- void CShaderAPIDx11::ClearColor3ub( unsigned char r, unsigned char g, unsigned char b ) { m_DynamicState.m_ClearColor[0] = r / 255.0f; m_DynamicState.m_ClearColor[1] = g / 255.0f; m_DynamicState.m_ClearColor[2] = b / 255.0f; m_DynamicState.m_ClearColor[3] = 1.0f; } void CShaderAPIDx11::ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) { m_DynamicState.m_ClearColor[0] = r / 255.0f; m_DynamicState.m_ClearColor[1] = g / 255.0f; m_DynamicState.m_ClearColor[2] = b / 255.0f; m_DynamicState.m_ClearColor[3] = a / 255.0f; } void CShaderAPIDx11::ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil, int renderTargetWidth, int renderTargetHeight ) { // NOTE: State change commit isn't necessary since clearing doesn't use state // IssueStateChanges(); // State changed... need to flush the dynamic buffer FlushBufferedPrimitives(); // FIXME: This implementation is totally bust0red [doesn't guarantee exact color specified] if ( bClearColor && D3D11DeviceContext() ) { ID3D11RenderTargetView* rt; for ( int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++ ) { rt = m_DynamicState.m_pRenderTargetViews[i]; if ( rt == NULL ) break; D3D11DeviceContext()->ClearRenderTargetView( rt, m_DynamicState.m_ClearColor ); } // finally, free the back buffer rt = GetTexture( m_hBackBuffer ).GetRenderTargetView(); D3D11DeviceContext()->ClearRenderTargetView( rt, m_DynamicState.m_ClearColor ); } if ( bClearDepth && D3D11DeviceContext() && m_DynamicState.m_pDepthStencilView ) { UINT clearFlags = 0; if ( bClearDepth ) { clearFlags |= D3D11_CLEAR_DEPTH; } if ( bClearStencil ) { clearFlags |= D3D11_CLEAR_STENCIL; } D3D11DeviceContext()->ClearDepthStencilView( m_DynamicState.m_pDepthStencilView, clearFlags, 1.0f, 0 ); } } //----------------------------------------------------------------------------- // Methods related to binding shaders //----------------------------------------------------------------------------- void CShaderAPIDx11::BindVertexShader( VertexShaderHandle_t hVertexShader ) { ID3D11VertexShader *pVertexShader = g_pShaderDeviceDx11->GetVertexShader( hVertexShader ); if ( m_DynamicState.m_pVertexShader != pVertexShader ) { SetStateFlag( STATE_CHANGED_VERTEXSHADER ); } if ( m_DynamicState.m_InputLayout.m_hVertexShader != hVertexShader ) { SetStateFlag( STATE_CHANGED_INPUTLAYOUT ); } m_DynamicState.m_pVertexShader = pVertexShader; m_DynamicState.m_InputLayout.m_hVertexShader = hVertexShader; } void CShaderAPIDx11::BindGeometryShader( GeometryShaderHandle_t hGeometryShader ) { ID3D11GeometryShader *pGeometryShader = g_pShaderDeviceDx11->GetGeometryShader( hGeometryShader ); if ( m_DynamicState.m_pGeometryShader != pGeometryShader ) { SetStateFlag( STATE_CHANGED_GEOMETRYSHADER ); } m_DynamicState.m_pGeometryShader = pGeometryShader; } void CShaderAPIDx11::BindPixelShader( PixelShaderHandle_t hPixelShader ) { ID3D11PixelShader *pPixelShader = g_pShaderDeviceDx11->GetPixelShader( hPixelShader ); if ( m_DynamicState.m_pPixelShader != pPixelShader ) { SetStateFlag( STATE_CHANGED_PIXELSHADER ); } m_DynamicState.m_pPixelShader = pPixelShader; } void CShaderAPIDx11::BindVertexBuffer( int nStreamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions ) { StatesDx11::DynamicState &dynamic = m_DynamicState; // FIXME: What to do about repetitions? CVertexBufferDx11 *pVertexBufferDx11 = static_cast( pVertexBuffer ); ID3D11Buffer *pBuffer = NULL; UINT stride = 0; if ( pVertexBufferDx11 ) { pBuffer = pVertexBufferDx11->GetDx11Buffer(); stride = pVertexBufferDx11->VertexSize(); } // Offset can be provided by first index if ( nOffsetInBytes < 0 ) { nOffsetInBytes = nFirstVertex * stride; } UINT offset = nOffsetInBytes; if ( pBuffer != dynamic.m_pVertexBuffer[nStreamID] ) { dynamic.m_pVertexBuffer[nStreamID] = pBuffer; SetStateFlag( STATE_CHANGED_VERTEXBUFFER ); } if ( stride != dynamic.m_pVBStrides[nStreamID] ) { dynamic.m_pVBStrides[nStreamID] = stride; SetStateFlag( STATE_CHANGED_VERTEXBUFFER ); } if ( offset != dynamic.m_pVBOffsets[nStreamID] ) { dynamic.m_pVBOffsets[nStreamID] = offset; SetStateFlag( STATE_CHANGED_VERTEXBUFFER ); } if ( nStreamID > dynamic.m_MaxVertexBuffer ) { dynamic.m_MaxVertexBuffer = nStreamID; if ( dynamic.m_MaxVertexBuffer > dynamic.m_PrevMaxVertexBuffer ) { SetStateFlag( STATE_CHANGED_VERTEXBUFFER ); } } if ( dynamic.m_InputLayout.m_pVertexDecl[nStreamID] != fmt ) { m_DynamicState.m_InputLayout.m_pVertexDecl[nStreamID] = fmt; SetStateFlag( STATE_CHANGED_INPUTLAYOUT ); } } void CShaderAPIDx11::SetUsingExtraVertexBuffers( bool bStaticLit, bool bUsingFlex, bool bUsingMorph ) { if ( m_DynamicState.m_InputLayout.m_bStaticLit != bStaticLit || m_DynamicState.m_InputLayout.m_bUsingFlex != bUsingFlex || m_DynamicState.m_InputLayout.m_bUsingMorph != bUsingMorph ) { SetStateFlag( STATE_CHANGED_INPUTLAYOUT ); } m_DynamicState.m_InputLayout.m_bStaticLit = bStaticLit; m_DynamicState.m_InputLayout.m_bUsingFlex = bUsingFlex; m_DynamicState.m_InputLayout.m_bUsingMorph = bUsingMorph; } void CShaderAPIDx11::BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes ) { CIndexBufferDx11 *pIndexBufferDx11 = static_cast( pIndexBuffer ); ID3D11Buffer *pBuffer = NULL; DXGI_FORMAT fmt = DXGI_FORMAT_R16_UINT; UINT offset = nOffsetInBytes; if ( pIndexBufferDx11 ) { pBuffer = pIndexBufferDx11->GetDx11Buffer(); fmt = ( pIndexBufferDx11->GetIndexFormat() == MATERIAL_INDEX_FORMAT_16BIT ) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; } if ( pBuffer != m_DynamicState.m_IndexBuffer.m_pBuffer || fmt != m_DynamicState.m_IndexBuffer.m_Format || offset != m_DynamicState.m_IndexBuffer.m_nOffset) { SetStateFlag( STATE_CHANGED_INDEXBUFFER ); } m_DynamicState.m_IndexBuffer.m_pBuffer = pBuffer; m_DynamicState.m_IndexBuffer.m_Format = fmt; m_DynamicState.m_IndexBuffer.m_nOffset = offset; } //----------------------------------------------------------------------------- // Unbinds resources because they are about to be deleted //----------------------------------------------------------------------------- void CShaderAPIDx11::Unbind( VertexShaderHandle_t hShader ) { ID3D11VertexShader *pShader = g_pShaderDeviceDx11->GetVertexShader( hShader ); Assert( pShader ); if ( m_DynamicState.m_pVertexShader == pShader ) { BindVertexShader( VERTEX_SHADER_HANDLE_INVALID ); } } void CShaderAPIDx11::Unbind( GeometryShaderHandle_t hShader ) { ID3D11GeometryShader *pShader = g_pShaderDeviceDx11->GetGeometryShader( hShader ); Assert( pShader ); if ( m_DynamicState.m_pGeometryShader == pShader ) { BindGeometryShader( GEOMETRY_SHADER_HANDLE_INVALID ); } } void CShaderAPIDx11::Unbind( PixelShaderHandle_t hShader ) { ID3D11PixelShader *pShader = g_pShaderDeviceDx11->GetPixelShader( hShader ); Assert( pShader ); if ( m_DynamicState.m_pPixelShader == pShader ) { BindPixelShader( PIXEL_SHADER_HANDLE_INVALID ); } } void CShaderAPIDx11::UnbindVertexBuffer( ID3D11Buffer *pBuffer ) { Assert( pBuffer ); for ( int i = 0; i < MAX_DX11_STREAMS; ++i ) { if ( m_DynamicState.m_pVertexBuffer[i] == pBuffer ) { BindVertexBuffer( i, NULL, 0, 0, 0, VERTEX_POSITION, 0 ); } } } void CShaderAPIDx11::UnbindIndexBuffer( ID3D11Buffer *pBuffer ) { Assert( pBuffer ); if ( m_DynamicState.m_IndexBuffer.m_pBuffer == pBuffer ) { BindIndexBuffer( NULL, 0 ); } } //----------------------------------------------------------------------------- // Sets the topology state //----------------------------------------------------------------------------- void CShaderAPIDx11::SetTopology( MaterialPrimitiveType_t topology ) { D3D11_PRIMITIVE_TOPOLOGY d3dTopology; switch ( topology ) { case MATERIAL_POINTS: d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; break; case MATERIAL_LINES: d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; break; case MATERIAL_TRIANGLES: d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break; case MATERIAL_TRIANGLE_STRIP: d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break; case MATERIAL_LINE_STRIP: d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP; break; default: case MATERIAL_LINE_LOOP: case MATERIAL_POLYGON: case MATERIAL_QUADS: Assert( 0 ); d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; break; } ////Log( "Set topology to %i\n", d3dTopology ); if ( d3dTopology != m_DynamicState.m_Topology ) { FlushBufferedPrimitives(); SetStateFlag( STATE_CHANGED_TOPOLOGY ); } m_DynamicState.m_Topology = d3dTopology; } //----------------------------------------------------------------------------- // Mesh/Material rendering //----------------------------------------------------------------------------- void CShaderAPIDx11::DrawMesh( IMesh *pMesh ) { VPROF( "CShaderAPIDx11::DrawMesh" ); if ( ShaderUtil()->GetConfig().m_bSuppressRendering ) return; //Log( "CShaderAPIDx11::DrawMesh %p\n", pMesh ); m_pMesh = static_cast( pMesh ); if ( !m_pMesh || !m_pMaterial ) { Warning( "Tried to render mesh with NULL mesh or NULL material!\n" ); return; } SetUsingExtraVertexBuffers( m_pMesh->HasColorMesh(), m_pMesh->HasFlexMesh(), m_pMaterial->IsUsingVertexID() ); m_pMaterial->DrawMesh( CompressionType( pMesh->GetVertexFormat() ) ); m_pMesh = NULL; } static int s_nPassesRendered = 0; // Begins a rendering pass that uses a state snapshot void CShaderAPIDx11::BeginPass( StateSnapshot_t snapshot ) { // Apply the snapshot state //if ( snapshot != -1 ) UseSnapshot( snapshot ); } // Renders a single pass of a material void CShaderAPIDx11::RenderPass( int nPass, int nPassCount ) { if ( g_pShaderDeviceDx11->IsDeactivated() ) return; //IssueStateChanges(); // Now actually render if ( m_pMesh ) { m_pMesh->RenderPass(); } else { Assert( 0 ); RenderPassWithVertexAndIndexBuffers(); } //m_CurrentSnapshot = -1; } void CShaderAPIDx11::RenderPassWithVertexAndIndexBuffers() { if ( m_DynamicState.m_Topology == D3D11_PRIMITIVE_TOPOLOGY_POINTLIST ) { Assert( 0 ); } else { //DrawIndexed(m_State.dynamic.m_IndexBuffer.) } } // Draws primitives void CShaderAPIDx11::Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount ) { //Log( "ShaderAPIDx11: Draw\n" ); SetTopology( primitiveType ); IssueStateChanges(); // FIXME: How do I set the base vertex location!? DrawIndexed( nFirstIndex, nIndexCount, 0 ); } void CShaderAPIDx11::DrawIndexed( int nFirstIndex, int nIndexCount, int nBaseVertexLocation ) { //Assert( m_State.dynamic.m_pVertexShader != NULL ); D3D11DeviceContext()->DrawIndexed( (UINT)nIndexCount, (UINT)nFirstIndex, (UINT)nBaseVertexLocation ); //g_pShaderDeviceDx11->Present(); //Log( "Presented" ); //Log( "\n" ); } void CShaderAPIDx11::DrawNotIndexed( int nFirstVertex, int nVertCount ) { D3D11DeviceContext()->Draw( (UINT)nVertCount, (UINT)nFirstVertex ); } //-----------------------------------------------------------------------------// bool CShaderAPIDx11::OnDeviceInit() { // Initialize the mesh manager MeshMgr()->Init(); int w, h; g_pShaderDeviceDx11->GetBackBufferDimensions( w, h ); { LOCK_SHADERAPI(); // Create a the back buffer view // UNDONE: Should texture creation and access be moved to ShaderDeviceDx11? ID3D11Texture2D *pBackBuffer; DXGI_SWAP_CHAIN_DESC swapChainDesc; D3D11SwapChain()->GetDesc( &swapChainDesc ); HRESULT hr = D3D11SwapChain()->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID *)&pBackBuffer ); if ( FAILED( hr ) ) return FALSE; m_hBackBuffer = CreateTextureHandle(); CTextureDx11 *pTex = &GetTexture( m_hBackBuffer ); pTex->SetupBackBuffer( w, h, "dx11BackBuffer", pBackBuffer, pTex->GetImageFormat( swapChainDesc.BufferDesc.Format ) ); } // Create the depth buffer m_hDepthBuffer = CreateDepthTexture( IMAGE_FORMAT_NV_DST24, w, h, "dx11DepthBuffer", true ); m_hPerFrameConstants = g_pShaderDeviceDx11->CreateConstantBuffer( sizeof( PerFrame_CBuffer_t ) ); m_hPerModelConstants = g_pShaderDeviceDx11->CreateConstantBuffer( sizeof( PerModel_CBuffer_t ) ); m_hPerSceneConstants = g_pShaderDeviceDx11->CreateConstantBuffer( sizeof( PerScene_CBuffer_t ) ); m_hSkinningConstants = g_pShaderDeviceDx11->CreateConstantBuffer( sizeof( Skinning_CBuffer_t ) ); m_hFlexConstants = g_pShaderDeviceDx11->CreateConstantBuffer( sizeof( Flex_CBuffer_t ) ); // Write some constants that don't change PerScene_CBuffer_t *pPerScene = (PerScene_CBuffer_t *)( (CShaderConstantBufferDx11 *)m_hPerSceneConstants )->GetData(); // [ gamma, overbright, 1/3, 1/overbright] pPerScene->cConstants.x = 1.0f / 2.2f; pPerScene->cConstants.y = OVERBRIGHT; pPerScene->cConstants.z = 1.0f / 3.0f; pPerScene->cConstants.w = 1.0f / OVERBRIGHT; pPerScene->cFlexScale.x = 1.0f; pPerScene->cFlexScale.y = 1.0f; pPerScene->cFlexScale.z = 0.0f; pPerScene->cFlexScale.w = 0.0f; ( (CShaderConstantBufferDx11 *)m_hPerSceneConstants )->ForceUpdate(); ResetRenderState( true ); return true; } void CShaderAPIDx11::OnDeviceShutdown() { for ( int i = 0; i < m_Textures.Count(); i++ ) { CTextureDx11 *pTex = &m_Textures[i]; pTex->Delete(); } m_Textures.RemoveAll(); } //----------------------------------------------------------------------------- // // Abandon all hope below this point // //----------------------------------------------------------------------------- bool CShaderAPIDx11::DoRenderTargetsNeedSeparateDepthBuffer() const { return false; } // Can we download textures? bool CShaderAPIDx11::CanDownloadTextures() const { if ( IsDeactivated() ) return false; return true; } // Used to clear the transition table when we know it's become invalid. void CShaderAPIDx11::ClearSnapshots() { LOCK_SHADERAPI(); FlushBufferedPrimitives(); g_pShaderShadowDx11->m_ShadowStates.RemoveAll(); ResetRenderState( true ); } // Sets the default *dynamic* state void CShaderAPIDx11::SetDefaultState() { m_DynamicState.m_MaxPSSampler = -1; m_DynamicState.m_MaxVSSampler = -1; m_DynamicState.m_pVertexShader = 0; m_DynamicState.m_pGeometryShader = 0; m_DynamicState.m_pPixelShader = 0; } // Returns the snapshot id for the current shadow state StateSnapshot_t CShaderAPIDx11::TakeSnapshot() { return g_pShaderShadowDx11->FindOrCreateSnapshot(); } void CShaderAPIDx11::OverrideAlphaWriteEnable(bool bOverrideEnable, bool bAlphaWriteEnable) { LOCK_SHADERAPI(); // NOT IMPLEMENTED } void CShaderAPIDx11::OverrideColorWriteEnable(bool bOverrideEnable, bool bColorWriteEnable) { LOCK_SHADERAPI(); // NOT IMPLEMENTED } // Returns true if the state snapshot is transparent bool CShaderAPIDx11::IsTranslucent( StateSnapshot_t id ) const { LOCK_SHADERAPI(); return g_pShaderShadowDx11->GetShadowState( id )->desc.blend.BlendEnabled(); } bool CShaderAPIDx11::IsAlphaTested( StateSnapshot_t id ) const { LOCK_SHADERAPI(); return false; //return g_pShaderShadowDx11->GetShadowState( id )->desc.bEnableAlphaTest; } bool CShaderAPIDx11::IsDepthWriteEnabled( StateSnapshot_t id ) const { LOCK_SHADERAPI(); return g_pShaderShadowDx11->GetShadowState( id )->desc.depthStencil.DepthWriteMask != 0; } bool CShaderAPIDx11::UsesVertexAndPixelShaders( StateSnapshot_t id ) const { // It has to in DX11 return true; } //----------------------------------------------------------------------------- // Gets the bound morph's vertex format; returns 0 if no morph is bound //----------------------------------------------------------------------------- MorphFormat_t CShaderAPIDx11::GetBoundMorphFormat() { return ShaderUtil()->GetBoundMorphFormat(); } //----------------------------------------------------------------------------- // What fields in the morph do we actually use? //----------------------------------------------------------------------------- MorphFormat_t CShaderAPIDx11::ComputeMorphFormat( int numSnapshots, StateSnapshot_t *pIds ) const { LOCK_SHADERAPI(); MorphFormat_t format = 0; for ( int i = 0; i < numSnapshots; ++i ) { MorphFormat_t fmt = g_pShaderShadowDx11->GetShadowState( pIds[i] )->desc.morphFormat; format |= VertexFlags( fmt ); } return format; } // Gets the vertex format for a set of snapshot ids VertexFormat_t CShaderAPIDx11::ComputeVertexFormat( int numSnapshots, StateSnapshot_t *pIds ) const { LOCK_SHADERAPI(); VertexFormat_t fmt = ComputeVertexUsage( numSnapshots, pIds ); return fmt; } // Gets the vertex format for a set of snapshot ids VertexFormat_t CShaderAPIDx11::ComputeVertexUsage( int num, StateSnapshot_t *pIds ) const { LOCK_SHADERAPI(); if ( num == 0 ) return 0; // We don't have to all sorts of crazy stuff if there's only one snapshot if ( num == 1 ) { const StatesDx11::ShadowState *state = g_pShaderShadowDx11->GetShadowState( pIds[0] ); return (VertexFormat_t)( state->desc.vertexFormat ); } Assert( pIds ); // Aggregating vertex formats is a little tricky; // For example, what do we do when two passes want user data? // Can we assume they are the same? For now, I'm going to // just print a warning in debug. VertexCompressionType_t compression = VERTEX_COMPRESSION_INVALID; int userDataSize = 0; int numBones = 0; int texCoordSize[VERTEX_MAX_TEXTURE_COORDINATES] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int flags = 0; for ( int i = num; --i >= 0; ) { //Log( "Applying vertex format from snapshot num %i, %i\n", i, pIds[i] ); const StatesDx11::ShadowState *state = g_pShaderShadowDx11->GetShadowState( pIds[i] ); VertexFormat_t fmt = state->desc.vertexFormat; flags |= VertexFlags( fmt ); VertexCompressionType_t newCompression = CompressionType( fmt ); if ( ( compression != newCompression ) && ( compression != VERTEX_COMPRESSION_INVALID ) ) { Warning( "Encountered a material with two passes that specify different vertex compression types!\n" ); compression = VERTEX_COMPRESSION_NONE; // Be safe, disable compression } int newNumBones = NumBoneWeights( fmt ); if ( ( numBones != newNumBones ) && ( newNumBones != 0 ) ) { if ( numBones != 0 ) { Warning( "Encountered a material with two passes that use different numbers of bones!\n" ); } numBones = newNumBones; } int newUserSize = UserDataSize( fmt ); if ( ( userDataSize != newUserSize ) && ( newUserSize != 0 ) ) { if ( userDataSize != 0 ) { Warning( "Encountered a material with two passes that use different user data sizes!\n" ); } userDataSize = newUserSize; } for ( int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j ) { int newSize = TexCoordSize( (TextureStage_t)j, fmt ); if ( ( texCoordSize[j] != newSize ) && ( newSize != 0 ) ) { if ( texCoordSize[j] != 0 ) { Warning( "Encountered a material with two passes that use different texture coord sizes!\n" ); } if ( texCoordSize[j] < newSize ) { texCoordSize[j] = newSize; } } } } return MeshMgr()->ComputeVertexFormat( flags, VERTEX_MAX_TEXTURE_COORDINATES, texCoordSize, numBones, userDataSize ); } // Uses a state snapshot void CShaderAPIDx11::UseSnapshot( StateSnapshot_t snapshot ) { const StatesDx11::ShadowState *curr = g_pShaderShadowDx11->GetShadowState( m_CurrentSnapshot ); const StatesDx11::ShadowState *entry = g_pShaderShadowDx11->GetShadowState( snapshot ); if ( entry->m_iBlendState != curr->m_iBlendState ) { SetStateFlag( STATE_CHANGED_BLEND ); } if ( entry->m_iDepthStencilState != curr->m_iDepthStencilState ) { SetStateFlag( STATE_CHANGED_DEPTHSTENCIL ); } if ( entry->m_iRasterState != curr->m_iRasterState ) { SetStateFlag( STATE_CHANGED_RASTERIZER ); } if ( entry->m_iVSConstantBufferState != curr->m_iVSConstantBufferState ) { SetStateFlag( STATE_CHANGED_VSCONSTANTBUFFERS ); } if ( entry->m_iGSConstantBufferState != curr->m_iGSConstantBufferState ) { SetStateFlag( STATE_CHANGED_GSCONSTANTBUFFERS ); } if ( entry->m_iPSConstantBufferState != curr->m_iPSConstantBufferState ) { SetStateFlag( STATE_CHANGED_PSCONSTANTBUFFERS ); } m_CurrentSnapshot = snapshot; } // Sets the color to modulate by void CShaderAPIDx11::Color3f( float r, float g, float b ) { } void CShaderAPIDx11::Color3fv( float const *pColor ) { } void CShaderAPIDx11::Color4f( float r, float g, float b, float a ) { } void CShaderAPIDx11::Color4fv( float const *pColor ) { } // Faster versions of color void CShaderAPIDx11::Color3ub( unsigned char r, unsigned char g, unsigned char b ) { } void CShaderAPIDx11::Color3ubv( unsigned char const *rgb ) { } void CShaderAPIDx11::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) { } void CShaderAPIDx11::Color4ubv( unsigned char const *rgba ) { } void CShaderAPIDx11::GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id ) { ShaderUtil()->GetStandardTextureDimensions( pWidth, pHeight, id ); } // Binds a particular material to render with void CShaderAPIDx11::Bind( IMaterial *pMaterial ) { LOCK_SHADERAPI(); IMaterialInternal *pMatInt = static_cast( pMaterial ); bool bMaterialChanged; if ( m_pMaterial && pMatInt && m_pMaterial->InMaterialPage() && pMatInt->InMaterialPage() ) { bMaterialChanged = ( m_pMaterial->GetMaterialPage() != pMatInt->GetMaterialPage() ); } else { bMaterialChanged = ( m_pMaterial != pMatInt ) || ( m_pMaterial && m_pMaterial->InMaterialPage() ) || ( pMatInt && pMatInt->InMaterialPage() ); } if ( bMaterialChanged ) { FlushBufferedPrimitives(); m_pMaterial = pMatInt; } } IMaterialInternal *CShaderAPIDx11::GetBoundMaterial() const { return m_pMaterial; } // Cull mode void CShaderAPIDx11::CullMode( MaterialCullMode_t cullMode ) { // This has to be set in shadow state Assert( 0 ); } D3D11_CULL_MODE CShaderAPIDx11::GetCullMode() const { return g_pShaderShadowDx11->GetShadowState( m_CurrentSnapshot )->desc.rasterizer.CullMode; } void CShaderAPIDx11::ForceDepthFuncEquals( bool bEnable ) { } // Forces Z buffering on or off void CShaderAPIDx11::OverrideDepthEnable( bool bEnable, bool bDepthEnable ) { } //legacy fast clipping linkage void CShaderAPIDx11::SetHeightClipZ( float z ) { } void CShaderAPIDx11::SetHeightClipMode( enum MaterialHeightClipMode_t heightClipMode ) { } // Sets the lights void CShaderAPIDx11::SetLight( int lightNum, const LightDesc_t &desc ) { LOCK_SHADERAPI(); //if ( ) //{ FlushBufferedPrimitives(); if ( !m_ShaderState.light.m_bLightChanged && FastMemCompare( &desc, &m_ShaderState.light.m_Lights[lightNum], sizeof( LightDesc_t ) ) ) { m_ShaderState.light.m_bLightChanged = true; } m_ShaderState.light.m_Lights[lightNum] = desc; m_ShaderState.light.m_NumLights = ComputeNumLights(); //m_ShaderState.light.m_bLightChanged = true; //SortLights(); //if ( lightNum == 2 && desc.m_Type != MATERIAL_LIGHT_DISABLE) // DebuggerBreak(); //m_ShaderState.light.m_bLightChanged = true; //} } void CShaderAPIDx11::SetAmbientLightCube( Vector4D cube[6] ) { LOCK_SHADERAPI(); if ( !m_ShaderState.light.m_bAmbientChanged && FastMemCompare( m_ShaderState.light.m_AmbientLightCube, cube, sizeof( VectorAligned ) * 6 ) ) { m_ShaderState.light.m_bAmbientChanged = true; } memcpy( m_ShaderState.light.m_AmbientLightCube, cube, 6 * sizeof( VectorAligned ) ); } // Get lights int CShaderAPIDx11::GetMaxLights( void ) const { return HardwareConfig()->MaxNumLights(); } const LightDesc_t &CShaderAPIDx11::GetLight( int lightNum ) const { return m_ShaderState.light.m_Lights[lightNum]; } int CShaderAPIDx11::GetCurrentLightCombo( void ) const { // UNUSED return 0; } void CShaderAPIDx11::DisableAllLocalLights() { LOCK_SHADERAPI(); bool bFlushed = false; for ( int lightNum = 0; lightNum < MAX_NUM_LIGHTS; lightNum++ ) { if ( m_ShaderState.light.m_Lights[lightNum].m_Type != MATERIAL_LIGHT_DISABLE ) { if ( !bFlushed ) { FlushBufferedPrimitives(); bFlushed = true; } m_ShaderState.light.m_Lights[lightNum].m_Type = MATERIAL_LIGHT_DISABLE; m_ShaderState.light.m_bLightChanged = true; } } m_ShaderState.light.m_NumLights = 0; } float CShaderAPIDx11::GetAmbientLightCubeLuminance( void ) { Vector4DAligned vLuminance( 0.3f, 0.59f, 0.11f, 0.0f ); float fLuminance = 0.0f; for ( int i = 0; i < 6; i++ ) { fLuminance += vLuminance.Dot( m_ShaderState.light.m_AmbientLightCube[i].Base() ); } return fLuminance / 6.0f; } void CShaderAPIDx11::SetSkinningMatrices() { } float CShaderAPIDx11::GetLightMapScaleFactor() const { switch ( HardwareConfig()->GetHDRType() ) { case HDR_TYPE_FLOAT: return 1.0; break; case HDR_TYPE_INTEGER: return 16.0; case HDR_TYPE_NONE: default: return GammaToLinearFullRange( 2.0 ); // light map scale } } // Gets the lightmap dimensions void CShaderAPIDx11::GetLightmapDimensions( int *w, int *h ) { g_pShaderUtil->GetLightmapDimensions( w, h ); } // Flushes any primitives that are buffered void CShaderAPIDx11::FlushBufferedPrimitives() { if ( ShaderUtil() ) { if ( !ShaderUtil()->OnFlushBufferedPrimitives() ) { return; } } LOCK_SHADERAPI(); // This shouldn't happen in the inner rendering loop! //Assert( m_pMesh == 0 ); // NOTE: We've gotta store off the matrix mode because // it'll get reset by the default state application caused by the flush MaterialMatrixMode_t oldMatMode = m_MatrixMode; MeshMgr()->Flush(); m_MatrixMode = oldMatMode; } // Creates/destroys Mesh IMesh *CShaderAPIDx11::CreateStaticMesh( VertexFormat_t fmt, const char *pTextureBudgetGroup, IMaterial *pMaterial ) { return MeshMgr()->CreateStaticMesh( fmt, pTextureBudgetGroup, pMaterial ); } void CShaderAPIDx11::DestroyStaticMesh( IMesh *mesh ) { MeshMgr()->DestroyStaticMesh( mesh ); } // Gets the dynamic mesh; note that you've got to render the mesh // before calling this function a second time. Clients should *not* // call DestroyStaticMesh on the mesh returned by this call. IMesh *CShaderAPIDx11::GetDynamicMesh( IMaterial *pMaterial, int nHWSkinBoneCount, bool buffered, IMesh *pVertexOverride, IMesh *pIndexOverride ) { return MeshMgr()->GetDynamicMesh( pMaterial, 0, nHWSkinBoneCount, buffered, pVertexOverride, pIndexOverride ); } IMesh *CShaderAPIDx11::GetDynamicMeshEx( IMaterial *pMaterial, VertexFormat_t fmt, int nHWSkinBoneCount, bool buffered, IMesh *pVertexOverride, IMesh *pIndexOverride ) { return MeshMgr()->GetDynamicMesh( pMaterial, fmt, nHWSkinBoneCount, buffered, pVertexOverride, pIndexOverride ); } IVertexBuffer *CShaderAPIDx11::GetDynamicVertexBuffer( IMaterial *pMaterial, bool buffered ) { return MeshMgr()->GetDynamicVertexBuffer( pMaterial, buffered ); } IIndexBuffer *CShaderAPIDx11::GetDynamicIndexBuffer( IMaterial *pMaterial, bool buffered ) { return MeshMgr()->GetDynamicIndexBuffer( pMaterial, buffered ); } IMesh *CShaderAPIDx11::GetFlexMesh() { return MeshMgr()->GetFlexMesh(); } bool CShaderAPIDx11::IsDeactivated() const { return g_pShaderDeviceDx11->IsDeactivated(); } // stuff related to matrix stacks // // Note Dx11 doesn't have a matrix stack, you just supply // the matrices to the shader in a constant buffer, so we will // not break compatibility with Dx9 and just emulate the behavior. bool CShaderAPIDx11::MatrixIsChanging() { if ( IsDeactivated() ) { return false; } if ( m_MatrixMode == MATERIAL_MODEL || m_MatrixMode == MATERIAL_VIEW || m_MatrixMode == MATERIAL_PROJECTION ) { FlushBufferedPrimitives(); } return true; } void CShaderAPIDx11::HandleMatrixModified() { m_ShaderState.m_ChangedMatrices[m_MatrixMode] = true; if ( m_MatrixMode == MATERIAL_MODEL ) { // The model matrix is also the first bone matrix m_ShaderState.bone.m_bBonesChanged = true; } } static DirectX::XMMATRIX s_DXMatIdent = DirectX::XMMatrixIdentity(); DirectX::XMMATRIX &CShaderAPIDx11::GetMatrix( MaterialMatrixMode_t mode ) { CUtlStack &curStack = m_ShaderState.m_MatrixStacks[mode]; if ( !curStack.Count() ) { return s_DXMatIdent; } return m_ShaderState.m_MatrixStacks[mode].Top().m_Matrix; } DirectX::XMMATRIX &CShaderAPIDx11::GetCurrentMatrix() { return m_pCurMatrixItem->m_Matrix; } DirectX::XMMATRIX CShaderAPIDx11::GetMatrixCopy( MaterialMatrixMode_t mode ) const { const CUtlStack &curStack = m_ShaderState.m_MatrixStacks[mode]; if ( !curStack.Count() ) { return DirectX::XMMatrixIdentity(); } return m_ShaderState.m_MatrixStacks[mode].Top().m_Matrix; } DirectX::XMMATRIX CShaderAPIDx11::GetCurrentMatrixCopy() const { return m_pCurMatrixItem->m_Matrix; } void CShaderAPIDx11::MatrixMode( MaterialMatrixMode_t matrixMode ) { Assert( m_ShaderState.m_MatrixStacks[matrixMode].Count() ); m_MatrixMode = matrixMode; m_pCurMatrixItem = &m_ShaderState.m_MatrixStacks[matrixMode].Top(); } void CShaderAPIDx11::PushMatrix() { // Does nothing in Dx11 //GetCurrentMatrix() = DirectX::XMMatrixTranspose( GetCurrentMatrix() ); CUtlStack &curStack = m_ShaderState.m_MatrixStacks[m_MatrixMode]; Assert( curStack.Count() ); int iNew = m_ShaderState.m_MatrixStacks[m_MatrixMode].Push(); curStack[iNew] = curStack[iNew - 1]; m_pCurMatrixItem = &m_ShaderState.m_MatrixStacks[m_MatrixMode].Top(); HandleMatrixModified(); } void CShaderAPIDx11::PopMatrix() { MatrixIsChanging(); Assert( m_ShaderState.m_MatrixStacks[m_MatrixMode].Count() > 1 ); m_ShaderState.m_MatrixStacks[m_MatrixMode].Pop(); m_pCurMatrixItem = &m_ShaderState.m_MatrixStacks[m_MatrixMode].Top(); HandleMatrixModified(); } void CShaderAPIDx11::LoadMatrix( float *m ) { MatrixIsChanging(); DirectX::XMFLOAT4X4 flt4x4( m ); GetCurrentMatrix() = DirectX::XMLoadFloat4x4( &flt4x4 ); HandleMatrixModified(); } void CShaderAPIDx11::LoadBoneMatrix( int boneIndex, const float *m ) { // NOTE: Bone matrices are column major, and HLSL is column-major, // so we don't have to transpose anything. m_ShaderState.bone.m_BoneMatrix[boneIndex] = DirectX::XMFLOAT3X4A( m ); m_ShaderState.bone.m_bBonesChanged = true; if ( boneIndex > m_ShaderState.bone.m_MaxBoneLoaded ) { m_ShaderState.bone.m_MaxBoneLoaded = boneIndex; } if ( boneIndex == 0 ) { // We have to transpose here because when loading // the model matrix into the shader it gets transposed again. MatrixMode( MATERIAL_MODEL ); VMatrix boneMatrix; boneMatrix.Init( *(matrix3x4_t *)m ); MatrixTranspose( boneMatrix, boneMatrix ); LoadMatrix( boneMatrix.Base() ); } } void CShaderAPIDx11::MultMatrix( float *m ) { MatrixIsChanging(); DirectX::XMFLOAT4X4 flt4x4( m ); GetCurrentMatrix() = DirectX::XMMatrixMultiply( GetCurrentMatrix(), DirectX::XMLoadFloat4x4( &flt4x4 ) ); HandleMatrixModified(); } void CShaderAPIDx11::MultMatrixLocal( float *m ) { MatrixIsChanging(); // DX11FIXME: Local multiply DirectX::XMFLOAT4X4 flt4x4( m ); GetCurrentMatrix() = DirectX::XMMatrixMultiply( DirectX::XMLoadFloat4x4( &flt4x4 ), GetCurrentMatrix() ); HandleMatrixModified(); } void CShaderAPIDx11::GetMatrix( MaterialMatrixMode_t matrixMode, float *dst ) { DirectX::XMFLOAT4X4 flt4x4; DirectX::XMStoreFloat4x4( &flt4x4, GetMatrix( matrixMode ) ); memcpy( dst, &flt4x4, sizeof( DirectX::XMFLOAT4X4 ) ); } void CShaderAPIDx11::GetMatrix( MaterialMatrixMode_t matrixMode, DirectX::XMMATRIX &mat ) { mat = GetMatrix( matrixMode ); } void CShaderAPIDx11::LoadIdentity( void ) { MatrixIsChanging(); m_pCurMatrixItem->m_Matrix = DirectX::XMMatrixIdentity(); HandleMatrixModified(); } void CShaderAPIDx11::LoadCameraToWorld( void ) { MatrixIsChanging(); DirectX::XMMATRIX inv; inv = DirectX::XMMatrixInverse( NULL, GetMatrix( MATERIAL_VIEW ) ); DirectX::XMFLOAT4X4 flt4x4inv; DirectX::XMStoreFloat4x4( &flt4x4inv, inv ); // Kill translation flt4x4inv.m[3][0] = flt4x4inv.m[3][1] = flt4x4inv.m[3][2] = 0.0f; inv = DirectX::XMLoadFloat4x4( &flt4x4inv ); m_pCurMatrixItem->m_Matrix = inv; HandleMatrixModified(); } // Get the current camera position in world space. void CShaderAPIDx11::GetWorldSpaceCameraPosition( float *pPos ) const { DirectX::XMFLOAT4X4 flt4x4; const DirectX::XMMATRIX &view = GetMatrixCopy( MATERIAL_VIEW ); DirectX::XMStoreFloat4x4( &flt4x4, view ); memcpy( pPos, &flt4x4, sizeof( DirectX::XMFLOAT4X4 ) ); } void CShaderAPIDx11::Ortho( double left, double top, double right, double bottom, double zNear, double zFar ) { MatrixIsChanging(); DirectX::XMMATRIX mat = DirectX::XMMatrixOrthographicOffCenterRH( left, right, bottom, top, zNear, zFar ); // DX11FIXME: Local multiply GetCurrentMatrix() = DirectX::XMMatrixMultiply( mat, GetCurrentMatrix() ); HandleMatrixModified(); } void CShaderAPIDx11::PerspectiveX( double fovx, double aspect, double zNear, double zFar ) { MatrixIsChanging(); float width = 2 * zNear * tan( fovx * M_PI / 360.0 ); float height = width / aspect; DirectX::XMMATRIX mat; mat = DirectX::XMMatrixPerspectiveRH( width, height, zNear, zFar ); // DX11FIXME: Local multiply GetCurrentMatrix() = DirectX::XMMatrixMultiply( mat, GetCurrentMatrix() ); HandleMatrixModified(); } void CShaderAPIDx11::PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right ) { MatrixIsChanging(); float width = 2 * zNear * tan( fovx * M_PI / 360.0 ); float height = width / aspect; // bottom, top, left, right are 0..1 so convert to -1..1 float flFrontPlaneLeft = -( width / 2.0f ) * ( 1.0f - left ) + left * ( width / 2.0f ); float flFrontPlaneRight = -( width / 2.0f ) * ( 1.0f - right ) + right * ( width / 2.0f ); float flFrontPlaneBottom = -( height / 2.0f ) * ( 1.0f - bottom ) + bottom * ( height / 2.0f ); float flFrontPlaneTop = -( height / 2.0f ) * ( 1.0f - top ) + top * ( height / 2.0f ); DirectX::XMMATRIX mat; mat = DirectX::XMMatrixPerspectiveOffCenterRH( flFrontPlaneLeft, flFrontPlaneRight, flFrontPlaneBottom, flFrontPlaneTop, zNear, zFar ); // DX11FIXME: Local multiply GetCurrentMatrix() = DirectX::XMMatrixMultiply( mat, GetCurrentMatrix() ); HandleMatrixModified(); } void CShaderAPIDx11::PickMatrix( int x, int y, int width, int height ) { MatrixIsChanging(); ShaderViewport_t viewport; GetViewports( &viewport, 1 ); int vx = viewport.m_nTopLeftX; int vy = viewport.m_nTopLeftX; int vwidth = viewport.m_nWidth; int vheight = viewport.m_nHeight; // Compute the location of the pick region in projection space... float px = 2.0 * (float)( x - vx ) / (float)vwidth - 1; float py = 2.0 * (float)( y - vy ) / (float)vheight - 1; float pw = 2.0 * (float)width / (float)vwidth; float ph = 2.0 * (float)height / (float)vheight; // we need to translate (px, py) to the origin // and scale so (pw,ph) -> (2, 2) DirectX::XMMATRIX mat; mat = DirectX::XMMatrixTranslation( -2.0f * py / ph, -2.0f * px / pw, 0.0f ); mat = DirectX::XMMatrixMultiply( mat, DirectX::XMMatrixScaling( 2.0f / pw, 2.0f / ph, 1.0f ) ); // DX11FIXME: Local multiply GetCurrentMatrix() = DirectX::XMMatrixMultiply( mat, GetCurrentMatrix() ); HandleMatrixModified(); } void CShaderAPIDx11::Rotate( float angle, float x, float y, float z ) { MatrixIsChanging(); DirectX::XMVECTOR axis; axis = DirectX::XMVectorSet( x, y, z, 0 ); // DX11FIXME: Local multiply GetCurrentMatrix() = DirectX::XMMatrixMultiply( DirectX::XMMatrixRotationAxis( axis, M_PI * angle / 180.0f ), GetCurrentMatrix() ); HandleMatrixModified(); } void CShaderAPIDx11::Translate( float x, float y, float z ) { MatrixIsChanging(); // DX11FIXME: Local multiply GetCurrentMatrix() = DirectX::XMMatrixMultiply( DirectX::XMMatrixTranslation( x, y, z ), GetCurrentMatrix() ); HandleMatrixModified(); } void CShaderAPIDx11::Scale( float x, float y, float z ) { MatrixIsChanging(); // DX11FIXME: Local multiply GetCurrentMatrix() = DirectX::XMMatrixMultiply( DirectX::XMMatrixScaling( x, y, z ), GetCurrentMatrix() ); HandleMatrixModified(); } void CShaderAPIDx11::ScaleXY( float x, float y ) { MatrixIsChanging(); // DX11FIXME: Local multiply GetCurrentMatrix() = DirectX::XMMatrixMultiply( DirectX::XMMatrixScaling( x, y, 1.0f ), GetCurrentMatrix() ); HandleMatrixModified(); } // Fog methods... void CShaderAPIDx11::FogMode( MaterialFogMode_t fogMode ) { if ( fogMode != m_ShaderState.fog.m_FogMode ) { m_ShaderState.fog.m_FogMode = fogMode; m_ShaderState.fog.m_bFogChanged = true; } } void CShaderAPIDx11::FogStart( float fStart ) { if ( fStart != m_ShaderState.fog.m_flFogStart ) { m_ShaderState.fog.m_flFogStart = fStart; m_ShaderState.fog.m_bFogChanged = true; } } void CShaderAPIDx11::FogEnd( float fEnd ) { if ( m_ShaderState.fog.m_flFogEnd != fEnd ) { m_ShaderState.fog.m_flFogStart = fEnd; m_ShaderState.fog.m_bFogChanged = true; } } void CShaderAPIDx11::SetFogZ( float fogZ ) { if ( m_ShaderState.fog.m_flFogZ != fogZ ) { m_ShaderState.fog.m_flFogZ = fogZ; m_ShaderState.fog.m_bFogChanged = true; } } void CShaderAPIDx11::FogMaxDensity( float flMaxDensity ) { if ( m_ShaderState.fog.m_flFogMaxDensity != flMaxDensity ) { m_ShaderState.fog.m_flFogMaxDensity = flMaxDensity; m_ShaderState.fog.m_bFogChanged = true; } } void CShaderAPIDx11::GetFogDistances( float *fStart, float *fEnd, float *fFogZ ) { *fStart = m_ShaderState.fog.m_flFogStart; *fEnd = m_ShaderState.fog.m_flFogEnd; *fFogZ = m_ShaderState.fog.m_flFogZ; } void CShaderAPIDx11::SceneFogColor3ub( unsigned char r, unsigned char g, unsigned char b ) { m_ShaderState.fog.m_FogColor[0] = r / 255.0f; m_ShaderState.fog.m_FogColor[1] = g / 255.0f; m_ShaderState.fog.m_FogColor[2] = b / 255.0f; m_ShaderState.fog.m_bFogChanged = true; } void CShaderAPIDx11::SceneFogMode( MaterialFogMode_t fogMode ) { if ( fogMode != m_ShaderState.fog.m_FogMode ) { m_ShaderState.fog.m_FogMode = fogMode; m_ShaderState.fog.m_bFogChanged = true; } } void CShaderAPIDx11::GetSceneFogColor( unsigned char *rgb ) { rgb[0] = (unsigned char)( m_ShaderState.fog.m_FogColor[0] * 255 ); rgb[1] = (unsigned char)( m_ShaderState.fog.m_FogColor[1] * 255 ); rgb[2] = (unsigned char)( m_ShaderState.fog.m_FogColor[2] * 255 ); } // Sigh... I don't understand why there's two different fog settings MaterialFogMode_t CShaderAPIDx11::GetSceneFogMode() { return m_ShaderState.fog.m_FogMode; } int CShaderAPIDx11::GetPixelFogCombo() { if ( m_ShaderState.fog.m_FogMode != MATERIAL_FOG_NONE ) return m_ShaderState.fog.m_FogMode - 1; else return MATERIAL_FOG_NONE; } void CShaderAPIDx11::FogColor3f( float r, float g, float b ) { } void CShaderAPIDx11::FogColor3fv( float const *rgb ) { } void CShaderAPIDx11::FogColor3ub( unsigned char r, unsigned char g, unsigned char b ) { } void CShaderAPIDx11::FogColor3ubv( unsigned char const *rgb ) { } void CShaderAPIDx11::GetFogColor( float *rgb ) { //const StatesDx11::ShadowState *state = g_pShaderShadowDx11->GetShadowState( m_CurrentSnapshot ); } void CShaderAPIDx11::GetFogParamsAndColor( float *fogParams, float *rgba ) { const StatesDx11::ShadowState *state = g_pShaderShadowDx11->GetShadowState( m_CurrentSnapshot ); // Compute fog parameters if ( GetSceneFogMode() != MATERIAL_FOG_NONE && state->desc.fogMode != SHADER_FOGMODE_DISABLED ) { float fStart = m_ShaderState.fog.m_flFogStart; float fEnd = m_ShaderState.fog.m_flFogEnd; fogParams[0] = fStart * 2; // fog begin distance fogParams[1] = fEnd * 1.5f; // fog end distance (fully fogged) fogParams[2] = clamp( m_ShaderState.fog.m_flFogMaxDensity, 0.0f, 1.0f ); // Max fog factor fogParams[3] = m_ShaderState.fog.m_flFogZ; // water height } else { //emulating MATERIAL_FOG_NONE by setting the parameters so that CalcRangeFog() always returns 0. Gets rid of a dynamic combo across the ps2x set. fogParams[0] = 1.0f; // begin fogParams[1] = 1.0f; // end fogParams[2] = 0.0f; // Max fog density fogParams[3] = 0.0f; // water height rgba[0] = 0.0f; rgba[1] = 0.0f; rgba[2] = 0.0f; rgba[3] = 0.0f; return; } // Compute fog color ShaderFogMode_t fogMode = state->desc.fogMode; bool bDisableFogGammaCorrection = state->desc.disableFogGammaCorrection; bool bShouldGammaCorrect = true; // By default, we'll gamma correct. unsigned char rgb[3] = { 0 }; switch ( fogMode ) { case SHADER_FOGMODE_BLACK: // Additive decals bShouldGammaCorrect = false; break; case SHADER_FOGMODE_OO_OVERBRIGHT: case SHADER_FOGMODE_GREY: // Mod2x decals rgb[0] = rgb[1] = rgb[2] = 128; break; case SHADER_FOGMODE_WHITE: // Multiplicative decals rgb[0] = rgb[1] = rgb[2] = 255; bShouldGammaCorrect = false; break; case SHADER_FOGMODE_FOGCOLOR: GetSceneFogColor( rgb ); // Scene fog color break; NO_DEFAULT } rgba[0] = rgb[0] / 255.0f; rgba[1] = rgb[1] / 255.0f; rgba[2] = rgb[2] / 255.0f; rgba[3] = 1.0f; bShouldGammaCorrect &= !bDisableFogGammaCorrection; if ( bShouldGammaCorrect ) { GammaCorrectFogColor( rgba ); } } void CShaderAPIDx11::GammaCorrectFogColor( float *rgb ) { bool bLinearSpace = g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT; bool bScaleFogByToneMappingScale = false;//g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER; float fr = rgb[0]; float fg = rgb[1]; float fb = rgb[2]; if ( bLinearSpace ) { fr = GammaToLinear( fr ); fg = GammaToLinear( fg ); fb = GammaToLinear( fb ); if ( bScaleFogByToneMappingScale ) { fr *= m_ShaderState.m_ToneMappingScale.x; // fg *= m_ShaderState.m_ToneMappingScale.x; // Linear fb *= m_ShaderState.m_ToneMappingScale.x; // } } else if ( bScaleFogByToneMappingScale ) { fr *= m_ShaderState.m_ToneMappingScale.w; // fg *= m_ShaderState.m_ToneMappingScale.w; // Gamma fb *= m_ShaderState.m_ToneMappingScale.w; // } fr = min( fr, 1.0f ); fg = min( fg, 1.0f ); fb = min( fb, 1.0f ); rgb[0] = fr; rgb[1] = fg; rgb[2] = fb; } // KMS MaterialFogMode_t CShaderAPIDx11::GetCurrentFogType( void ) const { return m_ShaderState.fog.m_FogMode; } // Sets the *dynamic* vertex and pixel shaders void CShaderAPIDx11::SetVertexShaderIndex( ShaderIndex_t vshIndex ) { ShaderManager()->SetVertexShaderIndex( vshIndex ); ShaderManager()->SetVertexShader( g_pShaderShadowDx11->GetShadowState( m_CurrentSnapshot )->desc.vertexShader ); } void CShaderAPIDx11::SetPixelShaderIndex( ShaderIndex_t pshIndex ) { ShaderManager()->SetPixelShaderIndex( pshIndex ); ShaderManager()->SetPixelShader( g_pShaderShadowDx11->GetShadowState( m_CurrentSnapshot )->desc.pixelShader ); } // Returns the nearest supported format ImageFormat CShaderAPIDx11::GetNearestSupportedFormat( ImageFormat fmt, bool bFilteringRequired /* = true */ ) const { return CTextureDx11::GetClosestSupportedImageFormatForD3D11( fmt ); } ImageFormat CShaderAPIDx11::GetNearestRenderTargetFormat( ImageFormat fmt ) const { return CTextureDx11::GetClosestSupportedImageFormatForD3D11( fmt ); } // Sets the texture state void CShaderAPIDx11::BindTexture( Sampler_t stage, ShaderAPITextureHandle_t textureHandle ) { CTextureDx11 *pTex = &GetTexture( textureHandle ); if ( !pTex ) return; StatesDx11::DynamicState &dynamic = m_DynamicState; ID3D11ShaderResourceView *pView = pTex->GetView(); ID3D11SamplerState *pSampler = pTex->GetSamplerState(); if ( pView != dynamic.m_ppTextures[stage] ) { dynamic.m_ppTextures[stage] = pView; SetStateFlag( STATE_CHANGED_TEXTURES ); } if ( pSampler != dynamic.m_ppSamplers[stage] ) { dynamic.m_ppSamplers[stage] = pSampler; SetStateFlag( STATE_CHANGED_SAMPLERS ); } if ( stage > dynamic.m_MaxPSSampler ) { dynamic.m_MaxPSSampler = stage; if ( dynamic.m_MaxPSSampler > dynamic.m_PrevMaxPSSampler ) { SetStateFlag( STATE_CHANGED_SAMPLERS | STATE_CHANGED_TEXTURES ); } } } void CShaderAPIDx11::UnbindTexture( ShaderAPITextureHandle_t textureHandle ) { CTextureDx11 *pTex = &GetTexture( textureHandle ); // Unbind the sampler int iSampler = -1; for ( int i = 0; i < m_DynamicState.m_MaxPSSampler + 1; i++ ) { if ( m_DynamicState.m_ppTextures[i] == pTex->GetView() ) { iSampler = i; break; } } if ( iSampler == -1 ) return; m_DynamicState.m_ppSamplers[iSampler] = NULL; m_DynamicState.m_ppTextures[iSampler] = NULL; int maxSampler = -1; for ( int i = 0; i < MAX_DX11_SAMPLERS; i++ ) { if ( m_DynamicState.m_ppTextures[i] != NULL ) { maxSampler = i; } } m_DynamicState.m_MaxPSSampler = maxSampler; SetStateFlag( STATE_CHANGED_SAMPLERS | STATE_CHANGED_TEXTURES ); } // Indicates we're going to be modifying this texture // TexImage2D, TexSubImage2D, TexWrap, TexMinFilter, and TexMagFilter // all use the texture specified by this function. void CShaderAPIDx11::ModifyTexture( ShaderAPITextureHandle_t textureHandle ) { LOCK_SHADERAPI(); // Can't do this if we're locked! Assert( m_ModifyTextureLockedLevel < 0 ); m_ModifyTextureHandle = textureHandle; // If we've got a multi-copy texture, we need to up the current copy count CTextureDx11 &tex = GetTexture( textureHandle ); if ( tex.m_NumCopies > 1 ) { // Each time we modify a texture, we'll want to switch texture // as soon as a TexImage2D call is made... tex.m_SwitchNeeded = true; } } void CShaderAPIDx11::AdvanceCurrentTextureCopy( ShaderAPITextureHandle_t texture ) { // May need to switch textures.... CTextureDx11 &tex = GetTexture( texture ); if ( tex.m_NumCopies > 1 ) { if ( ++tex.m_CurrentCopy >= tex.m_NumCopies ) tex.m_CurrentCopy = 0; // When the current copy changes, we need to make sure this texture // isn't bound to any stages any more; thereby guaranteeing the new // copy will be re-bound. UnbindTexture( texture ); } } //----------------------------------------------------------------------------- // Texture image upload // // level: mipmap level we are writing to // cubeFace: face of the cubemap/array texture we are writing to // dstFormat: unused // zOffset: not sure // width: image width // height image height // srcFormat: format of the source image data // bSrcIsTiled: is the source image a tiled image // imageData: pointer to the beginning of the source image data //----------------------------------------------------------------------------- void CShaderAPIDx11::TexImage2D( int level, int cubeFace, ImageFormat dstFormat, int zOffset, int width, int height, ImageFormat srcFormat, bool bSrcIsTiled, void *imageData ) { LOCK_SHADERAPI(); Assert( imageData ); ShaderAPITextureHandle_t hModifyTexture = m_ModifyTextureHandle; if ( !m_Textures.IsValidIndex( hModifyTexture ) ) { Log( "Invalid modify texture handle!\n" ); return; } //if ( zOffset != 0 ) //DebuggerBreak(); Assert( ( width <= g_pHardwareConfig->Caps().m_MaxTextureWidth ) && ( height <= g_pHardwareConfig->Caps().m_MaxTextureHeight ) ); // Blow off mip levels if we don't support mipmapping if ( !g_pHardwareConfig->SupportsMipmapping() && ( level > 0 ) ) { Log( "Trying to image mip but we don't support mips!\n" ); return; } // This test here just makes sure we don't try to download mipmap levels // if we weren't able to create them in the first place CTextureDx11 &tex = GetTexture( hModifyTexture ); if ( level >= tex.m_NumLevels ) { Log( "level >= tex.m_NumLevels\n" ); return; } // May need to switch textures.... if ( tex.m_SwitchNeeded ) { AdvanceCurrentTextureCopy( hModifyTexture ); tex.m_SwitchNeeded = false; } CTextureDx11::TextureLoadInfo_t info; info.m_TextureHandle = hModifyTexture; info.m_pTexture = GetD3DTexture( hModifyTexture ); info.m_pView = tex.GetView(); info.m_nLevel = level; info.m_nCopy = tex.m_CurrentCopy; info.m_CubeFaceID = (D3D11_TEXTURECUBE_FACE)cubeFace; info.m_nWidth = width; info.m_nHeight = height; info.m_nZOffset = zOffset; info.m_SrcFormat = srcFormat; info.m_pSrcData = (unsigned char *)imageData; tex.LoadTexImage( info ); } void CShaderAPIDx11::TexSubImage2D( int level, int cubeFace, int xOffset, int yOffset, int zOffset, int width, int height, ImageFormat srcFormat, int srcStride, bool bSrcIsTiled, void *imageData ) { //Log( "TexSubImage2D!\n" ); LOCK_SHADERAPI(); Assert( imageData ); ShaderAPITextureHandle_t hModifyTexture = m_ModifyTextureHandle; if ( !m_Textures.IsValidIndex( hModifyTexture ) ) { Log( "Invalid modify texture handle!\n" ); return; } //if ( zOffset != 0 ) //DebuggerBreak(); // Blow off mip levels if we don't support mipmapping if ( !g_pHardwareConfig->SupportsMipmapping() && ( level > 0 ) ) { Log( "Trying to image mip but we don't support mips!\n" ); return; } CTextureDx11 &tex = GetTexture( hModifyTexture ); // NOTE: This can only be done with procedural textures if this method is // being used to download the entire texture, cause last frame's partial update // may be in a completely different texture! Sadly, I don't have all of the // information I need, but I can at least check a couple things.... #ifdef _DEBUG if ( tex.m_NumCopies > 1 ) { Assert( ( xOffset == 0 ) && ( yOffset == 0 ) ); } #endif // This test here just makes sure we don't try to download mipmap levels // if we weren't able to create them in the first place if ( level >= tex.m_NumLevels ) { Log( "level >= tex.m_NumLevels\n" ); return; } // May need to switch textures.... if ( tex.m_SwitchNeeded ) { AdvanceCurrentTextureCopy( hModifyTexture ); tex.m_SwitchNeeded = false; } CTextureDx11::TextureLoadInfo_t info; info.m_TextureHandle = hModifyTexture; info.m_pTexture = GetD3DTexture( hModifyTexture ); info.m_pView = tex.GetView(); info.m_nLevel = level; info.m_nCopy = tex.m_CurrentCopy; info.m_CubeFaceID = (D3D11_TEXTURECUBE_FACE)cubeFace; info.m_nWidth = width; info.m_nHeight = height; info.m_nZOffset = zOffset; info.m_SrcFormat = srcFormat; info.m_pSrcData = (unsigned char *)imageData; tex.LoadTexImage( info, xOffset, yOffset, srcStride ); } void CShaderAPIDx11::TexImageFromVTF(IVTFTexture* pVTF, int iVTFFrame) { TexImage2D(0, 0, pVTF->Format(), 0, pVTF->Width(), pVTF->Height(), pVTF->Format(), false, pVTF->ImageData(iVTFFrame, 0, 0)); } bool CShaderAPIDx11::TexLock( int level, int cubeFaceID, int xOffset, int yOffset, int width, int height, CPixelWriter &writer ) { LOCK_SHADERAPI(); Assert( m_ModifyTextureHandle > 0 ); ShaderAPITextureHandle_t hTexture = m_ModifyTextureHandle; if ( !m_Textures.IsValidIndex( hTexture ) ) return false; // Blow off mip levels if we don't support mipmapping if ( !g_pHardwareConfig->SupportsMipmapping() && ( level > 0 ) ) return false; // This test here just makes sure we don't try to download mipmap levels // if we weren't able to create them in the first place CTextureDx11 &tex = GetTexture( hTexture ); if ( level >= tex.m_NumLevels ) { return false; } // May need to switch textures.... if ( tex.m_SwitchNeeded ) { AdvanceCurrentTextureCopy( hTexture ); tex.m_SwitchNeeded = false; } bool ret = tex.Lock( tex.m_CurrentCopy, level, cubeFaceID, xOffset, yOffset, width, height, false, writer ); if ( ret ) { m_ModifyTextureLockedLevel = level; m_ModifyTextureLockedFace = cubeFaceID; } return ret; } void CShaderAPIDx11::TexUnlock() { LOCK_SHADERAPI(); if ( m_ModifyTextureLockedLevel >= 0 ) { CTextureDx11 &tex = GetTexture( m_ModifyTextureHandle ); tex.Unlock( tex.m_CurrentCopy, m_ModifyTextureLockedLevel, m_ModifyTextureLockedFace ); m_ModifyTextureLockedLevel = -1; } } // These are bound to the texture, not the texture environment void CShaderAPIDx11::TexMinFilter( ShaderTexFilterMode_t texFilterMode ) { LOCK_SHADERAPI(); ShaderAPITextureHandle_t hModifyTexture = m_ModifyTextureHandle; if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) return; GetTexture( hModifyTexture ).SetMinFilter( texFilterMode ); } void CShaderAPIDx11::TexMagFilter( ShaderTexFilterMode_t texFilterMode ) { LOCK_SHADERAPI(); ShaderAPITextureHandle_t hModifyTexture = m_ModifyTextureHandle; if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) return; GetTexture( hModifyTexture ).SetMagFilter( texFilterMode ); } void CShaderAPIDx11::TexWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode ) { LOCK_SHADERAPI(); ShaderAPITextureHandle_t hModifyTexture = m_ModifyTextureHandle; if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) return; GetTexture( hModifyTexture ).SetWrap( coord, wrapMode ); } ShaderAPITextureHandle_t CShaderAPIDx11::CreateTexture( int width, int height, int depth, ImageFormat dstImageFormat, int numMipLevels, int numCopies, int flags, const char *pDebugName, const char *pTextureGroupName ) { Log( "Create Texture with format: %s\n", ImageLoader::GetName( dstImageFormat ) ); ShaderAPITextureHandle_t handle; CreateTextures( &handle, 1, width, height, depth, dstImageFormat, numMipLevels, numCopies, flags, pDebugName, pTextureGroupName ); return handle; } void CShaderAPIDx11::CreateTextureHandles( ShaderAPITextureHandle_t *handles, int count ) { if ( count <= 0 ) return; MEM_ALLOC_CREDIT(); int idxCreating = 0; ShaderAPITextureHandle_t hTexture; for ( hTexture = 0; hTexture < m_Textures.Count(); hTexture++ ) { if ( !( m_Textures[hTexture].m_nFlags & CTextureDx11::IS_ALLOCATED ) ) { handles[idxCreating++] = hTexture; if ( idxCreating >= count ) return; } } while ( idxCreating < count ) handles[idxCreating++] = m_Textures.AddToTail(); } void CShaderAPIDx11::CreateTextures( ShaderAPITextureHandle_t *pHandles, int count, int width, int height, int depth, ImageFormat dstImageFormat, int numMipLevels, int numCopies, int flags, const char *pDebugName, const char *pTextureGroupName ) { LOCK_SHADERAPI(); // Create a set of texture handles CreateTextureHandles( pHandles, count ); CTextureDx11 **arrTxp = new CTextureDx11 * [count]; Log( "Creating Textures with format: %s\n", ImageLoader::GetName( dstImageFormat ) ); for ( int idxFrame = 0; idxFrame < count; ++idxFrame ) { arrTxp[idxFrame] = &GetTexture( pHandles[idxFrame] ); CTextureDx11 *pTexture = arrTxp[idxFrame]; pTexture->SetupTexture2D( width, height, depth, count, idxFrame, flags, numCopies, numMipLevels, dstImageFormat ); pTexture->SetAnisotropicLevel( m_TexAnisotropy ); } delete[] arrTxp; } CTextureDx11 &CShaderAPIDx11::GetTexture( ShaderAPITextureHandle_t handle ) { return m_Textures[handle]; } ShaderAPITextureHandle_t CShaderAPIDx11::CreateTextureHandle() { ShaderAPITextureHandle_t handle; CreateTextureHandles( &handle, 1 ); return handle; } ShaderAPITextureHandle_t CShaderAPIDx11::CreateDepthTexture( ImageFormat renderFormat, int width, int height, const char *pDebugName, bool bTexture ) { LOCK_SHADERAPI(); ShaderAPITextureHandle_t i = CreateTextureHandle(); CTextureDx11 *pTexture = &GetTexture( i ); pTexture->SetupDepthTexture( renderFormat, width, height, pDebugName, bTexture ); return i; } void CShaderAPIDx11::DeleteTexture( ShaderAPITextureHandle_t textureHandle ) { LOCK_SHADERAPI(); if ( !TextureIsAllocated( textureHandle ) ) { // already deallocated return; } // Unbind it! // Delete it baby GetTexture( textureHandle ).Delete(); } bool CShaderAPIDx11::IsTexture( ShaderAPITextureHandle_t textureHandle ) { LOCK_SHADERAPI(); if ( !TextureIsAllocated( textureHandle ) ) return false; if ( GetTexture( textureHandle ).m_nFlags & CTextureDx11::IS_DEPTH_STENCIL ) { return GetTexture( textureHandle ).GetDepthStencilView() != 0; } else if ( ( GetTexture( textureHandle ).m_NumCopies == 1 && GetTexture( textureHandle ).GetTexture() != 0 ) || ( GetTexture( textureHandle ).m_NumCopies > 1 && GetTexture( textureHandle ).GetTexture( 0 ) != 0 ) ) { return true; } return false; } void CShaderAPIDx11::SetAnisotropicLevel( int nAnisotropyLevel ) { LOCK_SHADERAPI(); // NOTE: This must be called before the rest of the code in this function so // anisotropic can be set per-texture to force it on! This will also avoid // a possible infinite loop that existed before. g_pShaderUtil->NoteAnisotropicLevel( nAnisotropyLevel ); // Never set this to 1. In the case we want it set to 1, we will use this to override // aniso per-texture, so set it to something reasonable if ( nAnisotropyLevel > g_pHardwareConfig->Caps().m_nMaxAnisotropy || nAnisotropyLevel <= 1 ) { // Set it to 1/4 the max but between 2-8 nAnisotropyLevel = max( 2, min( 8, ( g_pHardwareConfig->Caps().m_nMaxAnisotropy / 4 ) ) ); } m_TexAnisotropy = nAnisotropyLevel; // Set the D3D max aninsotropy state for all samplers for ( ShaderAPITextureHandle_t handle = 0; handle < m_Textures.Count(); handle++ ) { CTextureDx11 &tex = GetTexture( handle ); tex.SetAnisotropicLevel( m_TexAnisotropy ); } } bool CShaderAPIDx11::IsTextureResident( ShaderAPITextureHandle_t textureHandle ) { return true; } // stuff that isn't to be used from within a shader void CShaderAPIDx11::ClearBuffersObeyStencil(bool bClearColor, bool bClearDepth) { ClearBuffersObeyStencilEx(bClearColor, bClearColor, bClearDepth); } // stuff that isn't to be used from within a shader void CShaderAPIDx11::ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth ) { LOCK_SHADERAPI(); if ( !bClearColor && !bClearDepth ) return; FlushBufferedPrimitives(); ShaderUtil()->DrawClearBufferQuad( m_DynamicState.m_ClearColor[0] * 255, m_DynamicState.m_ClearColor[1] * 255, m_DynamicState.m_ClearColor[2] * 255, m_DynamicState.m_ClearColor[3] * 255, bClearColor, bClearAlpha, bClearDepth ); FlushBufferedPrimitives(); } void CShaderAPIDx11::PerformFullScreenStencilOperation( void ) { } void CShaderAPIDx11::ReadPixels( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat ) { } void CShaderAPIDx11::ReadPixels( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *data, ImageFormat dstFormat, int nDstStride ) { } void CShaderAPIDx11::FlushHardware() { } // Set the number of bone weights void CShaderAPIDx11::SetNumBoneWeights( int numBones ) { LOCK_SHADERAPI(); if ( m_ShaderState.bone.m_NumBones != numBones ) { FlushBufferedPrimitives(); m_ShaderState.bone.m_NumBones = numBones; m_ShaderState.bone.m_bBonesChanged = true; } } //----------------------------------------------------------------------------- // Selection mode methods //----------------------------------------------------------------------------- int CShaderAPIDx11::SelectionMode( bool selectionMode ) { LOCK_SHADERAPI(); int numHits = m_NumHits; if ( m_InSelectionMode ) { WriteHitRecord(); } m_InSelectionMode = selectionMode; m_pCurrSelectionRecord = m_pSelectionBuffer; m_NumHits = 0; return numHits; } bool CShaderAPIDx11::IsInSelectionMode() const { return m_InSelectionMode; } void CShaderAPIDx11::SelectionBuffer( unsigned int *pBuffer, int size ) { LOCK_SHADERAPI(); Assert( !m_InSelectionMode ); Assert( pBuffer && size ); m_pSelectionBufferEnd = pBuffer + size; m_pSelectionBuffer = pBuffer; m_pCurrSelectionRecord = pBuffer; } void CShaderAPIDx11::ClearSelectionNames() { LOCK_SHADERAPI(); if ( m_InSelectionMode ) { WriteHitRecord(); } m_SelectionNames.Clear(); } void CShaderAPIDx11::LoadSelectionName( int name ) { LOCK_SHADERAPI(); if ( m_InSelectionMode ) { WriteHitRecord(); Assert( m_SelectionNames.Count() > 0 ); m_SelectionNames.Top() = name; } } void CShaderAPIDx11::PushSelectionName( int name ) { LOCK_SHADERAPI(); if ( m_InSelectionMode ) { WriteHitRecord(); m_SelectionNames.Push( name ); } } void CShaderAPIDx11::PopSelectionName() { LOCK_SHADERAPI(); if ( m_InSelectionMode ) { WriteHitRecord(); m_SelectionNames.Pop(); } } void CShaderAPIDx11::WriteHitRecord() { FlushBufferedPrimitives(); if ( m_SelectionNames.Count() && ( m_SelectionMinZ != FLT_MAX ) ) { Assert( m_pCurrSelectionRecord + m_SelectionNames.Count() + 3 < m_pSelectionBufferEnd ); *m_pCurrSelectionRecord++ = m_SelectionNames.Count(); *m_pCurrSelectionRecord++ = (int)( (double)m_SelectionMinZ * (double)0xFFFFFFFF ); *m_pCurrSelectionRecord++ = (int)( (double)m_SelectionMaxZ * (double)0xFFFFFFFF ); for ( int i = 0; i < m_SelectionNames.Count(); ++i ) { *m_pCurrSelectionRecord++ = m_SelectionNames[i]; } ++m_NumHits; } m_SelectionMinZ = FLT_MAX; m_SelectionMaxZ = FLT_MIN; } // We hit somefin in selection mode void CShaderAPIDx11::RegisterSelectionHit( float minz, float maxz ) { if ( minz < 0 ) minz = 0; if ( maxz > 1 ) maxz = 1; if ( m_SelectionMinZ > minz ) m_SelectionMinZ = minz; if ( m_SelectionMaxZ < maxz ) m_SelectionMaxZ = maxz; } // Use this to get the mesh builder that allows us to modify vertex data CMeshBuilder *CShaderAPIDx11::GetVertexModifyBuilder() { return &m_ModifyBuilder; } // Board-independent calls, here to unify how shaders set state // Implementations should chain back to IShaderUtil->BindTexture(), etc. void CShaderAPIDx11::CopyRenderTargetToScratchTexture(ShaderAPITextureHandle_t srcRt, ShaderAPITextureHandle_t dstTex, Rect_t* pSrcRect, Rect_t* pDstRect) { } //------------------------------------------------------------------------- // Allows locking and unlocking of very specific surface types. pOutBits and pOutPitch will not be touched if // the lock fails. //------------------------------------------------------------------------- void CShaderAPIDx11::LockRect(void** pOutBits, int* pOutPitch, ShaderAPITextureHandle_t texHandle, int mipmap, int x, int y, int w, int h, bool bWrite, bool bRead) { } void CShaderAPIDx11::UnlockRect(ShaderAPITextureHandle_t texHandle, int mipmap) { } // Use this to begin and end the frame void CShaderAPIDx11::BeginFrame() { } void CShaderAPIDx11::EndFrame() { } // returns the current time in seconds.... double CShaderAPIDx11::CurrentTime() const { return Sys_FloatTime(); } void CShaderAPIDx11::ForceHardwareSync( void ) { } void CShaderAPIDx11::SetClipPlane( int index, const float *pPlane ) { } void CShaderAPIDx11::EnableClipPlane( int index, bool bEnable ) { } void CShaderAPIDx11::SetFastClipPlane( const float *pPlane ) { } void CShaderAPIDx11::EnableFastClip( bool bEnable ) { } int CShaderAPIDx11::GetCurrentNumBones( void ) const { return m_ShaderState.bone.m_NumBones; } // Is hardware morphing enabled? bool CShaderAPIDx11::IsHWMorphingEnabled() const { return false; } int CShaderAPIDx11::MapLightComboToPSLightCombo( int nLightCombo ) const { return 0; } void CShaderAPIDx11::RecordString( const char *pStr ) { } void CShaderAPIDx11::DestroyVertexBuffers( bool bExitingLevel ) { LOCK_SHADERAPI(); MeshMgr()->DestroyVertexBuffers(); // After a map is shut down, we switch to using smaller dynamic VBs // (VGUI shouldn't need much), so that we have more memory free during map loading m_nDynamicVBSize = bExitingLevel ? DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL : DYNAMIC_VERTEX_BUFFER_MEMORY; } int CShaderAPIDx11::GetCurrentDynamicVBSize( void ) { return m_nDynamicVBSize; } void CShaderAPIDx11::EvictManagedResources() { } void CShaderAPIDx11::ReleaseShaderObjects() { } void CShaderAPIDx11::RestoreShaderObjects() { } void CShaderAPIDx11::SyncToken( const char *pToken ) { } // Rendering parameters void CShaderAPIDx11::SetFloatRenderingParameter( int parm_number, float value ) { LOCK_SHADERAPI(); if ( parm_number < ARRAYSIZE( FloatRenderingParameters ) ) FloatRenderingParameters[parm_number] = value; } void CShaderAPIDx11::SetIntRenderingParameter( int parm_number, int value ) { LOCK_SHADERAPI(); if ( parm_number < ARRAYSIZE( IntRenderingParameters ) ) IntRenderingParameters[parm_number] = value; } void CShaderAPIDx11::SetVectorRenderingParameter( int parm_number, Vector const &value ) { LOCK_SHADERAPI(); if ( parm_number < ARRAYSIZE( VectorRenderingParameters ) ) VectorRenderingParameters[parm_number] = value; } float CShaderAPIDx11::GetFloatRenderingParameter( int parm_number ) const { LOCK_SHADERAPI(); if ( parm_number < ARRAYSIZE( FloatRenderingParameters ) ) return FloatRenderingParameters[parm_number]; else return 0.0; } int CShaderAPIDx11::GetIntRenderingParameter( int parm_number ) const { LOCK_SHADERAPI(); if ( parm_number < ARRAYSIZE( IntRenderingParameters ) ) return IntRenderingParameters[parm_number]; else return 0; } Vector CShaderAPIDx11::GetVectorRenderingParameter( int parm_number ) const { LOCK_SHADERAPI(); if ( parm_number < ARRAYSIZE( VectorRenderingParameters ) ) return VectorRenderingParameters[parm_number]; else return Vector( 0, 0, 0 ); } // Stencils void CShaderAPIDx11::SetStencilEnable( bool onoff ) { //m_TargetState.shadow.depthStencil.StencilEnable = onoff; } void CShaderAPIDx11::SetStencilFailOperation( StencilOperation_t op ) { //m_TargetState.shadow.depthStencil.FrontFace.StencilFailOp = (D3D11_STENCIL_OP)op; } void CShaderAPIDx11::SetStencilZFailOperation( StencilOperation_t op ) { //m_TargetState.shadow.depthStencil.FrontFace.StencilDepthFailOp = (D3D11_STENCIL_OP)op; } void CShaderAPIDx11::SetStencilPassOperation( StencilOperation_t op ) { //m_TargetState.shadow.depthStencil.FrontFace.StencilPassOp = (D3D11_STENCIL_OP)op; } void CShaderAPIDx11::SetStencilCompareFunction( StencilComparisonFunction_t cmpfn ) { //m_TargetState.shadow.depthStencil.FrontFace.StencilFunc = (D3D11_COMPARISON_FUNC)cmpfn; } void CShaderAPIDx11::SetStencilReferenceValue( int ref ) { //m_TargetState.shadow.depthStencil.StencilRef = ref; } void CShaderAPIDx11::SetStencilTestMask( uint32 msk ) { //m_TargetState.shadow.depthStencil.StencilReadMask = msk; } void CShaderAPIDx11::SetStencilWriteMask( uint32 msk ) { //m_TargetState.shadow.depthStencil.StencilWriteMask = msk; } int CShaderAPIDx11::CompareSnapshots( StateSnapshot_t snapshot0, StateSnapshot_t snapshot1 ) { LOCK_SHADERAPI(); const StatesDx11::ShadowState *shadow0 = g_pShaderShadowDx11->GetShadowState( snapshot0 ); const StatesDx11::ShadowState *shadow1 = g_pShaderShadowDx11->GetShadowState( snapshot1 ); if ( shadow0 == shadow1 ) return 0; return shadow0 > shadow1 ? -1 : 1; } IDirect3DBaseTexture *CShaderAPIDx11::GetD3DTexture( ShaderAPITextureHandle_t handle ) { if ( handle == INVALID_SHADERAPI_TEXTURE_HANDLE ) return NULL; CTextureDx11 &tex = GetTexture( handle ); if ( tex.m_NumCopies == 1 ) return tex.GetTexture(); else return tex.GetTexture( tex.m_CurrentCopy ); } bool CShaderAPIDx11::SetMode( void *hwnd, int nAdapter, const ShaderDeviceInfo_t &mode ) { return g_pShaderDeviceMgr->SetMode( hwnd, nAdapter, mode ) != NULL; } //-------------------------------------------------------------------- // Occlusion queries //-------------------------------------------------------------------- ShaderAPIOcclusionQuery_t CShaderAPIDx11::CreateOcclusionQueryObject( void ) { return g_pShaderDeviceDx11->CreateOcclusionQuery(); } void CShaderAPIDx11::DestroyOcclusionQueryObject( ShaderAPIOcclusionQuery_t handle ) { g_pShaderDeviceDx11->DestroyOcclusionQuery( handle ); } void CShaderAPIDx11::BeginOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t handle ) { if ( handle != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE ) { D3D11DeviceContext()->Begin( (ID3D11Query *)handle ); } } void CShaderAPIDx11::EndOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t handle ) { if ( handle != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE ) { D3D11DeviceContext()->End( (ID3D11Query *)handle ); } } int CShaderAPIDx11::OcclusionQuery_GetNumPixelsRendered( ShaderAPIOcclusionQuery_t handle, bool bFlush ) { if ( handle == INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE ) { return OCCLUSION_QUERY_RESULT_ERROR; } uint64 nPixels; HRESULT hr = D3D11DeviceContext()->GetData( (ID3D11Query *)handle, &nPixels, sizeof( uint64 ), bFlush ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH ); if ( FAILED( hr ) ) { return OCCLUSION_QUERY_RESULT_ERROR; } if ( hr == S_FALSE ) // not ready yet { return OCCLUSION_QUERY_RESULT_PENDING; } return (int)nPixels; } void CShaderAPIDx11::BindStandardTexture( Sampler_t stage, StandardTextureId_t id ) { ShaderUtil()->BindStandardTexture( stage, id ); } void CShaderAPIDx11::BindVertexTexture( VertexTextureSampler_t stage, ShaderAPITextureHandle_t hTexture ) { CTextureDx11 *pTex = &GetTexture( hTexture ); if ( !pTex ) return; StatesDx11::DynamicState &dynamic = m_DynamicState; ID3D11ShaderResourceView *pView = pTex->GetView(); ID3D11SamplerState *pSampler = pTex->GetSamplerState(); if ( pView != dynamic.m_ppVertexTextures[stage] ) { dynamic.m_ppVertexTextures[stage] = pView; SetStateFlag( STATE_CHANGED_VERTEXTEXTURES ); } if ( pSampler != dynamic.m_ppVertexSamplers[stage] ) { dynamic.m_ppVertexSamplers[stage] = pSampler; SetStateFlag( STATE_CHANGED_VERTEXSAMPLERS ); } if ( stage > dynamic.m_MaxVSSampler ) { dynamic.m_MaxVSSampler = stage; if ( dynamic.m_MaxVSSampler > dynamic.m_PrevMaxVSSampler ) { SetStateFlag( STATE_CHANGED_VERTEXSAMPLERS | STATE_CHANGED_VERTEXTEXTURES ); } } } void CShaderAPIDx11::SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t *pWeights ) { LOCK_SHADERAPI(); //m_ShaderState.morph.m_nFirstWeight = nFirstWeight; //m_ShaderState.morph.m_nCount = nCount; //int numLoaded = nFirstWeight + nCount; //if ( numLoaded > m_ShaderState.morph.m_nMaxWeightLoaded ) //{ // m_ShaderState.morph.m_nMaxWeightLoaded = numLoaded; //} //memcpy( m_ShaderState.morph.m_pWeights + nFirstWeight, pWeights, sizeof( MorphWeight_t ) * nCount ); //m_ShaderState.morph.m_bMorphChanged = true; } void CShaderAPIDx11::SetToneMappingScaleLinear( const Vector &scale ) { // Flush buffered primitives before changing the tone map scalar! FlushBufferedPrimitives(); Vector4D old = m_ShaderState.m_ToneMappingScale; Vector scale_to_use = scale; m_ShaderState.m_ToneMappingScale.AsVector3D() = scale_to_use; bool mode_uses_srgb = false; switch ( HardwareConfig()->GetHDRType() ) { case HDR_TYPE_NONE: m_ShaderState.m_ToneMappingScale.x = 1.0; // output scale m_ShaderState.m_ToneMappingScale.z = 1.0; // reflection map scale break; case HDR_TYPE_FLOAT: m_ShaderState.m_ToneMappingScale.x = scale_to_use.x; // output scale m_ShaderState.m_ToneMappingScale.z = 1.0; // reflection map scale break; case HDR_TYPE_INTEGER: mode_uses_srgb = true; m_ShaderState.m_ToneMappingScale.x = scale_to_use.x; // output scale m_ShaderState.m_ToneMappingScale.z = 16.0; // reflection map scale break; } m_ShaderState.m_ToneMappingScale.y = GetLightMapScaleFactor(); // light map scale // w component gets gamma scale m_ShaderState.m_ToneMappingScale.w = LinearToGammaFullRange( m_ShaderState.m_ToneMappingScale.x ); if ( old != m_ShaderState.m_ToneMappingScale ) { m_ShaderState.m_bToneMappingScaleChanged = true; } } void CShaderAPIDx11::BindStandardVertexTexture( VertexTextureSampler_t stage, StandardTextureId_t id ) { ShaderUtil()->BindStandardVertexTexture( stage, id ); } template FORCEINLINE T GetData( uint8 const *pData ) { return *( reinterpret_cast( pData ) ); } void CShaderAPIDx11::ExecuteCommandBuffer( uint8 *pCmdBuf ) { uint8 *pReturnStack[20]; uint8 **pSP = &pReturnStack[ARRAYSIZE( pReturnStack )]; uint8 *pLastCmd; for ( ;;) { uint8 *pCmd = pCmdBuf; int nCmd = GetData( pCmdBuf ); switch ( nCmd ) { case CBCMD_END: { if ( pSP == &pReturnStack[ARRAYSIZE( pReturnStack )] ) return; else { // pop pc pCmdBuf = *( pSP++ ); break; } } case CBCMD_JUMP: pCmdBuf = GetData( pCmdBuf + sizeof( int ) ); break; case CBCMD_JSR: { Assert( pSP > &( pReturnStack[0] ) ); ExecuteCommandBuffer( GetData( pCmdBuf + sizeof( int ) ) ); pCmdBuf = pCmdBuf + sizeof( int ) + sizeof( uint8 * ); break; } case CBCMD_BIND_STANDARD_TEXTURE: { int nSampler = GetData( pCmdBuf + sizeof( int ) ); int nTextureID = GetData( pCmdBuf + 2 * sizeof( int ) ); pCmdBuf += 3 * sizeof( int ); ShaderUtil()->BindStandardTexture( (Sampler_t)nSampler, (StandardTextureId_t)nTextureID ); break; } case CBCMD_BIND_SHADERAPI_TEXTURE_HANDLE: { int nSampler = GetData( pCmdBuf + sizeof( int ) ); ShaderAPITextureHandle_t hTexture = GetData( pCmdBuf + 2 * sizeof( int ) ); Assert( hTexture != INVALID_SHADERAPI_TEXTURE_HANDLE ); pCmdBuf += 2 * sizeof( int ) + sizeof( ShaderAPITextureHandle_t ); BindTexture( (Sampler_t)nSampler, hTexture ); break; } case CBCMD_SET_PSHINDEX: { int nIdx = GetData( pCmdBuf + sizeof( int ) ); SetPixelShaderIndex( nIdx ); pCmdBuf += 2 * sizeof( int ); break; } case CBCMD_SET_VSHINDEX: { int nIdx = GetData( pCmdBuf + sizeof( int ) ); SetVertexShaderIndex( nIdx ); pCmdBuf += 2 * sizeof( int ); break; } #ifndef NDEBUG default: { Assert( 0 ); } #endif } pLastCmd = pCmd; } } bool CShaderAPIDx11::ShouldWriteDepthToDestAlpha() const { return IsPC() && g_pHardwareConfig->SupportsPixelShaders_2_b() && ( m_ShaderState.fog.m_FogMode != MATERIAL_FOG_LINEAR_BELOW_FOG_Z ) && ( GetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA ) != 0 ); } void CShaderAPIDx11::ClearVertexAndPixelShaderRefCounts() { LOCK_SHADERAPI(); ShaderManager()->ClearVertexAndPixelShaderRefCounts(); } void CShaderAPIDx11::PurgeUnusedVertexAndPixelShaders() { LOCK_SHADERAPI(); ShaderManager()->PurgeUnusedVertexAndPixelShaders(); } void CShaderAPIDx11::SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture ) { LOCK_SHADERAPI(); SetFlashlightStateEx( state, worldToTexture, NULL ); } void CShaderAPIDx11::SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture ) { LOCK_SHADERAPI(); bool bFlushed = false; if ( memcmp( &state, &m_FlashlightState, sizeof( FlashlightState_t ) ) ) { FlushBufferedPrimitives(); bFlushed = true; m_FlashlightState = state; m_bFlashlightStateChanged = true; } if ( worldToTexture != m_FlashlightWorldToTexture ) { if ( !bFlushed ) { FlushBufferedPrimitives(); bFlushed = true; } m_FlashlightWorldToTexture = worldToTexture; m_bFlashlightStateChanged = true; } if ( pFlashlightDepthTexture != m_pFlashlightDepthTexture ) { if ( !bFlushed ) { FlushBufferedPrimitives(); bFlushed = true; } m_pFlashlightDepthTexture = pFlashlightDepthTexture; m_bFlashlightStateChanged = true; } } const FlashlightState_t &CShaderAPIDx11::GetFlashlightState( VMatrix &worldToTexture ) const { worldToTexture = m_FlashlightWorldToTexture; return m_FlashlightState; } const FlashlightState_t &CShaderAPIDx11::GetFlashlightStateEx( VMatrix &worldToTexture, ITexture **pFlashlightDepthTexture ) const { worldToTexture = m_FlashlightWorldToTexture; *pFlashlightDepthTexture = m_pFlashlightDepthTexture; return m_FlashlightState; } #define MAX_LIGHTS 4 void CShaderAPIDx11::GetDX9LightState( LightState_t *state ) const { // hack . . do this a cheaper way. if ( m_ShaderState.light.m_AmbientLightCube[0][0] == 0.0f && m_ShaderState.light.m_AmbientLightCube[0][1] == 0.0f && m_ShaderState.light.m_AmbientLightCube[0][2] == 0.0f && m_ShaderState.light.m_AmbientLightCube[1][0] == 0.0f && m_ShaderState.light.m_AmbientLightCube[1][1] == 0.0f && m_ShaderState.light.m_AmbientLightCube[1][2] == 0.0f && m_ShaderState.light.m_AmbientLightCube[2][0] == 0.0f && m_ShaderState.light.m_AmbientLightCube[2][1] == 0.0f && m_ShaderState.light.m_AmbientLightCube[2][2] == 0.0f && m_ShaderState.light.m_AmbientLightCube[3][0] == 0.0f && m_ShaderState.light.m_AmbientLightCube[3][1] == 0.0f && m_ShaderState.light.m_AmbientLightCube[3][2] == 0.0f && m_ShaderState.light.m_AmbientLightCube[4][0] == 0.0f && m_ShaderState.light.m_AmbientLightCube[4][1] == 0.0f && m_ShaderState.light.m_AmbientLightCube[4][2] == 0.0f && m_ShaderState.light.m_AmbientLightCube[5][0] == 0.0f && m_ShaderState.light.m_AmbientLightCube[5][1] == 0.0f && m_ShaderState.light.m_AmbientLightCube[5][2] == 0.0f ) { state->m_bAmbientLight = false; } else { state->m_bAmbientLight = true; } Assert( m_pMesh ); Assert( m_ShaderState.light.m_NumLights <= 4 ); if ( g_pHardwareConfig->SupportsPixelShaders_2_b() ) { Assert( m_ShaderState.light.m_NumLights <= MAX_LIGHTS ); // 2b hardware gets four lights } else { Assert( m_ShaderState.light.m_NumLights <= ( MAX_LIGHTS - 2 ) ); // 2.0 hardware gets two less } state->m_nNumLights = m_ShaderState.light.m_NumLights; state->m_bStaticLightVertex = m_pMesh->HasColorMesh(); state->m_bStaticLightTexel = false; // For now } void CShaderAPIDx11::CopyRenderTargetToTextureEx( ShaderAPITextureHandle_t textureHandle, int nRenderTargetID, Rect_t *pSrcRect, Rect_t *pDstRect ) { // don't use this return; // LOCK_SHADERAPI(); //VPROF_BUDGET( "CShaderAPIDx11::CopyRenderTargetToTexture", "Refraction overhead" ); /*if ( !TextureIsAllocated( textureHandle ) ) return; CTextureDx11 *pTexture = &GetTexture( textureHandle ); Assert( pTexture ); ID3D11Resource *pD3DTexture = pTexture->GetTexture(); Assert( pD3DTexture ); ITexture *rt = g_pShaderUtil->GetRenderTargetEx( nRenderTargetID ); CTextureDx11 *pTextureRT; if ( rt == NULL ) { pTextureRT = &GetTexture( 0 ); // copy back buffer } else { ITextureInternal* texInt = static_cast(rt); ShaderAPITextureHandle_t texHandle = texInt->GetTextureHandle( 0 ); pTextureRT = &GetTexture( texHandle ); } ID3D11Resource *pD3DTextureRT = pTextureRT->GetTexture(); Assert( pD3DTextureRT );*/ // need to draw a quad with the texture and downscale it } void CShaderAPIDx11::CopyTextureToRenderTargetEx(int nRenderTargetID, ShaderAPITextureHandle_t textureHandle, Rect_t* pSrcRect, Rect_t* pDstRect) { // don't use this return; // LOCK_SHADERAPI(); //VPROF_BUDGET( "CShaderAPIDx11::CopyRenderTargetToTexture", "Refraction overhead" ); /*if (!TextureIsAllocated(textureHandle)) return; CTextureDx11* pTexture = &GetTexture(textureHandle); Assert(pTexture); ID3D11Resource* pD3DTexture = pTexture->GetTexture(); Assert(pD3DTexture); ITexture* rt = g_pShaderUtil->GetRenderTargetEx(nRenderTargetID); CTextureDx11* pTextureRT; if (rt == NULL) { pTextureRT = &GetTexture(0); // copy back buffer } else { ITextureInternal* texInt = static_cast(rt); ShaderAPITextureHandle_t texHandle = texInt->GetTextureHandle(0); pTextureRT = &GetTexture(texHandle); } ID3D11Resource* pD3DTextureRT = pTextureRT->GetTexture(); Assert(pD3DTextureRT);*/ // need to draw a quad with the texture and downscale it } //------------------------------------------------------------------------------------ // UNUSED/UNSUPPORTED FUNCTIONS!!! //------------------------------------------------------------------------------------ // Lightmap texture binding void CShaderAPIDx11::BindLightmap( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::BindBumpLightmap( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::BindFullbrightLightmap( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::BindWhite( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::BindBlack( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::BindGrey( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::SetTextureTransformDimension( TextureStage_t textureStage, int dimension, bool projected ) { //Warning( "Unsupported CShaderAPIDx11::SetTextureTransformDimension() called!\n" ); } void CShaderAPIDx11::SetBumpEnvMatrix( TextureStage_t textureStage, float m00, float m01, float m10, float m11 ) { //Warning( "Unsupported CShaderAPIDx11::SetBumpEnvMatrix() called!\n" ); } void CShaderAPIDx11::SetAmbientLight( float r, float g, float b ) { //Warning( "Unsupported CShaderAPIDx11::SetAmbientLight() called!\n" ); } //----------------------------------------------------------------------------- // Methods related to state objects //----------------------------------------------------------------------------- void CShaderAPIDx11::SetRasterState( const ShaderRasterState_t &state ) { //Warning( "Unsupported CShaderAPIDx11::SetRasterState() called!\n" ); } // The shade mode void CShaderAPIDx11::ShadeMode( ShaderShadeMode_t mode ) { //Warning( "Unsupported CShaderAPIDx11::ShadeMode() called!\n" ); } void CShaderAPIDx11::TexSetPriority( int priority ) { //Warning( "Unsupported CShaderAPIDx11::SetTexPriority() called!\n" ); } // Sets the constant register for vertex and pixel shaders void CShaderAPIDx11::SetVertexShaderConstant( int var, float const *pVec, int numConst, bool bForce ) { } void CShaderAPIDx11::SetPixelShaderConstant( int var, float const *pVec, int numConst, bool bForce ) { } void CShaderAPIDx11::SetPixelShaderFogParams( int psReg ) { } bool CShaderAPIDx11::InFlashlightMode() const { return ShaderUtil()->InFlashlightMode(); } bool CShaderAPIDx11::InEditorMode() const { return ShaderUtil()->InEditorMode(); } void CShaderAPIDx11::InvalidateDelayedShaderConstants( void ) { //Warning( "Unsupported CShaderAPIDx11::InvalidateDelayedShaderConstants() called!\n" ); } //Set's the linear->gamma conversion textures to use for this hardware for both srgb writes enabled and disabled(identity) void CShaderAPIDx11::SetLinearToGammaConversionTextures( ShaderAPITextureHandle_t hSRGBWriteEnabledTexture, ShaderAPITextureHandle_t hIdentityTexture ) { //Warning( "Unsupported CShaderAPIDx11::SetLinearToGammaConversionTextures() called!\n" ); } // Special system flat normal map binding. void CShaderAPIDx11::BindFlatNormalMap( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::BindNormalizationCubeMap( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::BindSignedNormalizationCubeMap( TextureStage_t stage ) { // Unused } void CShaderAPIDx11::BindFBTexture( TextureStage_t stage, int textureIndex ) { // Unused } // Render state for the ambient light cube (vertex shaders) void CShaderAPIDx11::SetVertexShaderStateAmbientLightCube() { //Warning( "Unsupported CShaderAPIDx11::SetVertexShaderStateAmbientLightCube() called!\n" ); }