You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1256 lines
38 KiB
1256 lines
38 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
#define DISABLE_PROTECTED_THINGS |
|
#include "togl/rendermechanism.h" |
|
#include "shaderdevicebase.h" |
|
#include "tier1/KeyValues.h" |
|
#include "tier1/convar.h" |
|
#include "tier1/utlbuffer.h" |
|
#include "tier0/icommandline.h" |
|
#include "tier2/tier2.h" |
|
#include "filesystem.h" |
|
#include "datacache/idatacache.h" |
|
#include "shaderapi/ishaderutil.h" |
|
#include "shaderapibase.h" |
|
#include "shaderapi/ishadershadow.h" |
|
#include "shaderapi_global.h" |
|
#include "winutils.h" |
|
|
|
#ifdef _X360 |
|
#include "xbox/xbox_win32stubs.h" |
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Globals |
|
//----------------------------------------------------------------------------- |
|
IShaderUtil* g_pShaderUtil; // The main shader utility interface |
|
CShaderDeviceBase *g_pShaderDevice; |
|
CShaderDeviceMgrBase *g_pShaderDeviceMgr; |
|
CShaderAPIBase *g_pShaderAPI; |
|
IShaderShadow *g_pShaderShadow; |
|
|
|
bool g_bUseShaderMutex = false; // Shader mutex globals |
|
bool g_bShaderAccessDisallowed; |
|
CShaderMutex g_ShaderMutex; |
|
|
|
//----------------------------------------------------------------------------- |
|
// FIXME: Hack related to setting command-line values for convars. Remove!!! |
|
//----------------------------------------------------------------------------- |
|
class CShaderAPIConVarAccessor : public IConCommandBaseAccessor |
|
{ |
|
public: |
|
virtual bool RegisterConCommandBase( ConCommandBase *pCommand ) |
|
{ |
|
// Link to engine's list instead |
|
g_pCVar->RegisterConCommand( pCommand ); |
|
|
|
char const *pValue = g_pCVar->GetCommandLineValue( pCommand->GetName() ); |
|
if( pValue && !pCommand->IsCommand() ) |
|
{ |
|
( ( ConVar * )pCommand )->SetValue( pValue ); |
|
} |
|
return true; |
|
} |
|
}; |
|
|
|
static void InitShaderAPICVars( ) |
|
{ |
|
static CShaderAPIConVarAccessor g_ConVarAccessor; |
|
if ( g_pCVar ) |
|
{ |
|
ConVar_Register( FCVAR_MATERIAL_SYSTEM_THREAD, &g_ConVarAccessor ); |
|
} |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Read dx support levels |
|
//----------------------------------------------------------------------------- |
|
#if defined( DX_TO_GL_ABSTRACTION ) |
|
#if defined( OSX ) |
|
// OSX |
|
#define SUPPORT_CFG_FILE "dxsupport_mac.cfg" |
|
// TODO: make this different for Mac? |
|
#define SUPPORT_CFG_OVERRIDE_FILE "dxsupport_override.cfg" |
|
#else |
|
// Linux/Win GL |
|
#define SUPPORT_CFG_FILE "dxsupport_linux.cfg" |
|
// TODO: make this different for Linux? |
|
#define SUPPORT_CFG_OVERRIDE_FILE "dxsupport_override.cfg" |
|
#endif |
|
#else |
|
// D3D |
|
#define SUPPORT_CFG_FILE "dxsupport.cfg" |
|
#define SUPPORT_CFG_OVERRIDE_FILE "dxsupport_override.cfg" |
|
#endif |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// constructor, destructor |
|
//----------------------------------------------------------------------------- |
|
CShaderDeviceMgrBase::CShaderDeviceMgrBase() |
|
{ |
|
m_pDXSupport = NULL; |
|
} |
|
|
|
CShaderDeviceMgrBase::~CShaderDeviceMgrBase() |
|
{ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Factory used to get at internal interfaces (used by shaderapi + shader dlls) |
|
//----------------------------------------------------------------------------- |
|
static CreateInterfaceFn s_TempFactory; |
|
void *ShaderDeviceFactory( const char *pName, int *pReturnCode ) |
|
{ |
|
if (pReturnCode) |
|
{ |
|
*pReturnCode = IFACE_OK; |
|
} |
|
|
|
void *pInterface = s_TempFactory( pName, pReturnCode ); |
|
if ( pInterface ) |
|
return pInterface; |
|
|
|
pInterface = Sys_GetFactoryThis()( pName, pReturnCode ); |
|
if ( pInterface ) |
|
return pInterface; |
|
|
|
if ( pReturnCode ) |
|
{ |
|
*pReturnCode = IFACE_FAILED; |
|
} |
|
return NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Connect, disconnect |
|
//----------------------------------------------------------------------------- |
|
bool CShaderDeviceMgrBase::Connect( CreateInterfaceFn factory ) |
|
{ |
|
LOCK_SHADERAPI(); |
|
|
|
Assert( !g_pShaderDeviceMgr ); |
|
|
|
s_TempFactory = factory; |
|
|
|
// Connection/convar registration |
|
CreateInterfaceFn actualFactory = ShaderDeviceFactory; |
|
ConnectTier1Libraries( &actualFactory, 1 ); |
|
InitShaderAPICVars(); |
|
ConnectTier2Libraries( &actualFactory, 1 ); |
|
g_pShaderUtil = (IShaderUtil*)ShaderDeviceFactory( SHADER_UTIL_INTERFACE_VERSION, NULL ); |
|
g_pShaderDeviceMgr = this; |
|
|
|
s_TempFactory = NULL; |
|
|
|
if ( !g_pShaderUtil || !g_pFullFileSystem || !g_pShaderDeviceMgr ) |
|
{ |
|
Warning( "ShaderAPIDx10 was unable to access the required interfaces!\n" ); |
|
return false; |
|
} |
|
|
|
// NOTE! : Overbright is 1.0 so that Hammer will work properly with the white bumped and unbumped lightmaps. |
|
MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); |
|
return true; |
|
} |
|
|
|
void CShaderDeviceMgrBase::Disconnect() |
|
{ |
|
LOCK_SHADERAPI(); |
|
|
|
g_pShaderDeviceMgr = NULL; |
|
g_pShaderUtil = NULL; |
|
DisconnectTier2Libraries(); |
|
ConVar_Unregister(); |
|
DisconnectTier1Libraries(); |
|
|
|
if ( m_pDXSupport ) |
|
{ |
|
m_pDXSupport->deleteThis(); |
|
m_pDXSupport = NULL; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Query interface |
|
//----------------------------------------------------------------------------- |
|
void *CShaderDeviceMgrBase::QueryInterface( const char *pInterfaceName ) |
|
{ |
|
if ( !Q_stricmp( pInterfaceName, SHADER_DEVICE_MGR_INTERFACE_VERSION ) ) |
|
return ( IShaderDeviceMgr* )this; |
|
if ( !Q_stricmp( pInterfaceName, MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION ) ) |
|
return ( IMaterialSystemHardwareConfig* )g_pHardwareConfig; |
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the hardware caps for a particular adapter |
|
//----------------------------------------------------------------------------- |
|
const HardwareCaps_t& CShaderDeviceMgrBase::GetHardwareCaps( int nAdapter ) const |
|
{ |
|
Assert( ( nAdapter >= 0 ) && ( nAdapter < GetAdapterCount() ) ); |
|
return m_Adapters[nAdapter].m_ActualCaps; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Utility methods for reading config scripts |
|
//----------------------------------------------------------------------------- |
|
static inline int ReadHexValue( KeyValues *pVal, const char *pName ) |
|
{ |
|
const char *pString = pVal->GetString( pName, NULL ); |
|
if (!pString) |
|
{ |
|
return -1; |
|
} |
|
|
|
char *pTemp; |
|
int nVal = strtol( pString, &pTemp, 16 ); |
|
return (pTemp != pString) ? nVal : -1; |
|
} |
|
|
|
static bool ReadBool( KeyValues *pGroup, const char *pKeyName, bool bDefault ) |
|
{ |
|
int nVal = pGroup->GetInt( pKeyName, -1 ); |
|
if ( nVal != -1 ) |
|
{ |
|
// Warning( "\t%s = %s\n", pKeyName, (nVal != false) ? "true" : "false" ); |
|
return (nVal != false); |
|
} |
|
return bDefault; |
|
} |
|
|
|
static void ReadInt( KeyValues *pGroup, const char *pKeyName, int nInvalidValue, int *pResult ) |
|
{ |
|
int nVal = pGroup->GetInt( pKeyName, nInvalidValue ); |
|
if ( nVal != nInvalidValue ) |
|
{ |
|
*pResult = nVal; |
|
// Warning( "\t%s = %d\n", pKeyName, *pResult ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Utility method to copy over a keyvalue |
|
//----------------------------------------------------------------------------- |
|
static void AddKey( KeyValues *pDest, KeyValues *pSrc ) |
|
{ |
|
// Note this will replace already-existing values |
|
switch( pSrc->GetDataType() ) |
|
{ |
|
case KeyValues::TYPE_NONE: |
|
break; |
|
case KeyValues::TYPE_STRING: |
|
pDest->SetString( pSrc->GetName(), pSrc->GetString() ); |
|
break; |
|
case KeyValues::TYPE_INT: |
|
pDest->SetInt( pSrc->GetName(), pSrc->GetInt() ); |
|
break; |
|
case KeyValues::TYPE_FLOAT: |
|
pDest->SetFloat( pSrc->GetName(), pSrc->GetFloat() ); |
|
break; |
|
case KeyValues::TYPE_PTR: |
|
pDest->SetPtr( pSrc->GetName(), pSrc->GetPtr() ); |
|
break; |
|
case KeyValues::TYPE_WSTRING: |
|
pDest->SetWString( pSrc->GetName(), pSrc->GetWString() ); |
|
break; |
|
case KeyValues::TYPE_COLOR: |
|
pDest->SetColor( pSrc->GetName(), pSrc->GetColor() ); |
|
break; |
|
default: |
|
Assert( 0 ); |
|
break; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Finds if we have a dxlevel-specific config in the support keyvalues |
|
//----------------------------------------------------------------------------- |
|
KeyValues *CShaderDeviceMgrBase::FindDXLevelSpecificConfig( KeyValues *pKeyValues, int nDxLevel ) |
|
{ |
|
KeyValues *pGroup = pKeyValues->GetFirstSubKey(); |
|
for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() ) |
|
{ |
|
int nFoundDxLevel = pGroup->GetInt( "name", 0 ); |
|
if( nFoundDxLevel == nDxLevel ) |
|
return pGroup; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Finds if we have a dxlevel and vendor-specific config in the support keyvalues |
|
//----------------------------------------------------------------------------- |
|
KeyValues *CShaderDeviceMgrBase::FindDXLevelAndVendorSpecificConfig( KeyValues *pKeyValues, int nDxLevel, int nVendorID ) |
|
{ |
|
if ( IsX360() ) |
|
{ |
|
// 360 unique dxlevel implies hw config, vendor variance not applicable |
|
return NULL; |
|
} |
|
|
|
KeyValues *pGroup = pKeyValues->GetFirstSubKey(); |
|
for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() ) |
|
{ |
|
int nFoundDxLevel = pGroup->GetInt( "name", 0 ); |
|
int nFoundVendorID = ReadHexValue( pGroup, "VendorID" ); |
|
if( nFoundDxLevel == nDxLevel && nFoundVendorID == nVendorID ) |
|
return pGroup; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Finds if we have a vendor-specific config in the support keyvalues |
|
//----------------------------------------------------------------------------- |
|
KeyValues *CShaderDeviceMgrBase::FindCPUSpecificConfig( KeyValues *pKeyValues, int nCPUMhz, bool bAMD ) |
|
{ |
|
if ( IsX360() ) |
|
{ |
|
// 360 unique dxlevel implies hw config, cpu variance not applicable |
|
return NULL; |
|
} |
|
|
|
for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() ) |
|
{ |
|
const char *pName = pGroup->GetString( "name", NULL ); |
|
if ( !pName ) |
|
continue; |
|
|
|
if ( ( bAMD && Q_stristr( pName, "AMD" ) ) || |
|
( !bAMD && Q_stristr( pName, "Intel" ) ) ) |
|
{ |
|
int nMinMegahertz = pGroup->GetInt( "min megahertz", -1 ); |
|
int nMaxMegahertz = pGroup->GetInt( "max megahertz", -1 ); |
|
if( nMinMegahertz == -1 || nMaxMegahertz == -1 ) |
|
continue; |
|
|
|
if( nMinMegahertz <= nCPUMhz && nCPUMhz < nMaxMegahertz ) |
|
return pGroup; |
|
} |
|
} |
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Finds if we have a vendor-specific config in the support keyvalues |
|
//----------------------------------------------------------------------------- |
|
KeyValues *CShaderDeviceMgrBase::FindCardSpecificConfig( KeyValues *pKeyValues, int nVendorId, int nDeviceId ) |
|
{ |
|
if ( IsX360() ) |
|
{ |
|
// 360 unique dxlevel implies hw config, vendor variance not applicable |
|
return NULL; |
|
} |
|
|
|
KeyValues *pGroup = pKeyValues->GetFirstSubKey(); |
|
for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() ) |
|
{ |
|
int nFoundVendorId = ReadHexValue( pGroup, "VendorID" ); |
|
int nFoundDeviceIdMin = ReadHexValue( pGroup, "MinDeviceID" ); |
|
int nFoundDeviceIdMax = ReadHexValue( pGroup, "MaxDeviceID" ); |
|
if ( nFoundVendorId == nVendorId && nDeviceId >= nFoundDeviceIdMin && nDeviceId <= nFoundDeviceIdMax ) |
|
return pGroup; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Finds if we have a vendor-specific config in the support keyvalues |
|
//----------------------------------------------------------------------------- |
|
KeyValues *CShaderDeviceMgrBase::FindMemorySpecificConfig( KeyValues *pKeyValues, int nSystemRamMB ) |
|
{ |
|
if ( IsX360() ) |
|
{ |
|
// 360 unique dxlevel implies hw config, memory variance not applicable |
|
return NULL; |
|
} |
|
|
|
for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() ) |
|
{ |
|
// Used to help us debug this code |
|
// const char *pDebugName = pGroup->GetString( "name", "blah" ); |
|
|
|
int nMinMB = pGroup->GetInt( "min megabytes", -1 ); |
|
int nMaxMB = pGroup->GetInt( "max megabytes", -1 ); |
|
if ( nMinMB == -1 || nMaxMB == -1 ) |
|
continue; |
|
|
|
if ( nMinMB <= nSystemRamMB && nSystemRamMB < nMaxMB ) |
|
return pGroup; |
|
} |
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Finds if we have a texture mem size specific config |
|
//----------------------------------------------------------------------------- |
|
KeyValues *CShaderDeviceMgrBase::FindVidMemSpecificConfig( KeyValues *pKeyValues, int nVideoRamMB ) |
|
{ |
|
if ( IsX360() ) |
|
{ |
|
// 360 unique dxlevel implies hw config, vidmem variance not applicable |
|
return NULL; |
|
} |
|
|
|
for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() ) |
|
{ |
|
int nMinMB = pGroup->GetInt( "min megatexels", -1 ); |
|
int nMaxMB = pGroup->GetInt( "max megatexels", -1 ); |
|
if ( nMinMB == -1 || nMaxMB == -1 ) |
|
continue; |
|
|
|
if ( nMinMB <= nVideoRamMB && nVideoRamMB < nMaxMB ) |
|
return pGroup; |
|
} |
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Methods related to reading DX support levels given particular devices |
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Reads in the dxsupport.cfg keyvalues |
|
//----------------------------------------------------------------------------- |
|
static void OverrideValues_R( KeyValues *pDest, KeyValues *pSrc ) |
|
{ |
|
// Any same-named values get overridden in pDest. |
|
for ( KeyValues *pSrcValue=pSrc->GetFirstValue(); pSrcValue; pSrcValue=pSrcValue->GetNextValue() ) |
|
{ |
|
// Shouldn't be a container for more keys. |
|
Assert( pSrcValue->GetDataType() != KeyValues::TYPE_NONE ); |
|
AddKey( pDest, pSrcValue ); |
|
} |
|
|
|
// Recurse. |
|
for ( KeyValues *pSrcDir=pSrc->GetFirstTrueSubKey(); pSrcDir; pSrcDir=pSrcDir->GetNextTrueSubKey() ) |
|
{ |
|
Assert( pSrcDir->GetDataType() == KeyValues::TYPE_NONE ); |
|
|
|
KeyValues *pDestDir = pDest->FindKey( pSrcDir->GetName() ); |
|
if ( pDestDir && pDestDir->GetDataType() == KeyValues::TYPE_NONE ) |
|
{ |
|
OverrideValues_R( pDestDir, pSrcDir ); |
|
} |
|
} |
|
} |
|
|
|
static KeyValues * FindMatchingGroup( KeyValues *pSrc, KeyValues *pMatch ) |
|
{ |
|
KeyValues *pMatchSubKey = pMatch->FindKey( "name" ); |
|
bool bHasSubKey = ( pMatchSubKey && ( pMatchSubKey->GetDataType() != KeyValues::TYPE_NONE ) ); |
|
const char *name = bHasSubKey ? pMatchSubKey->GetString() : NULL; |
|
int nMatchVendorID = ReadHexValue( pMatch, "VendorID" ); |
|
int nMatchMinDeviceID = ReadHexValue( pMatch, "MinDeviceID" ); |
|
int nMatchMaxDeviceID = ReadHexValue( pMatch, "MaxDeviceID" ); |
|
|
|
KeyValues *pSrcGroup = NULL; |
|
for ( pSrcGroup = pSrc->GetFirstTrueSubKey(); pSrcGroup; pSrcGroup = pSrcGroup->GetNextTrueSubKey() ) |
|
{ |
|
if ( name ) |
|
{ |
|
KeyValues *pSrcGroupName = pSrcGroup->FindKey( "name" ); |
|
Assert( pSrcGroupName ); |
|
Assert( pSrcGroupName->GetDataType() != KeyValues::TYPE_NONE ); |
|
if ( Q_stricmp( pSrcGroupName->GetString(), name ) ) |
|
continue; |
|
} |
|
|
|
if ( nMatchVendorID >= 0 ) |
|
{ |
|
int nVendorID = ReadHexValue( pSrcGroup, "VendorID" ); |
|
if ( nMatchVendorID != nVendorID ) |
|
continue; |
|
} |
|
|
|
if ( nMatchMinDeviceID >= 0 && nMatchMaxDeviceID >= 0 ) |
|
{ |
|
int nMinDeviceID = ReadHexValue( pSrcGroup, "MinDeviceID" ); |
|
int nMaxDeviceID = ReadHexValue( pSrcGroup, "MaxDeviceID" ); |
|
if ( nMinDeviceID < 0 || nMaxDeviceID < 0 ) |
|
continue; |
|
|
|
if ( nMatchMinDeviceID > nMinDeviceID || nMatchMaxDeviceID < nMaxDeviceID ) |
|
continue; |
|
} |
|
|
|
return pSrcGroup; |
|
} |
|
return NULL; |
|
} |
|
|
|
static void OverrideKeyValues( KeyValues *pDst, KeyValues *pSrc ) |
|
{ |
|
KeyValues *pSrcGroup = NULL; |
|
for ( pSrcGroup = pSrc->GetFirstTrueSubKey(); pSrcGroup; pSrcGroup = pSrcGroup->GetNextTrueSubKey() ) |
|
{ |
|
// Match each group in pSrc to one in pDst containing the same "name" value: |
|
KeyValues * pDstGroup = FindMatchingGroup( pDst, pSrcGroup ); |
|
//Assert( pDstGroup ); |
|
if ( pDstGroup ) |
|
{ |
|
OverrideValues_R( pDstGroup, pSrcGroup ); |
|
} |
|
} |
|
|
|
// if( CommandLine()->FindParm( "-debugdxsupport" ) ) |
|
// { |
|
// CUtlBuffer tmpBuf; |
|
// pDst->RecursiveSaveToFile( tmpBuf, 0 ); |
|
// g_pFullFileSystem->WriteFile( "gary.txt", NULL, tmpBuf ); |
|
// } |
|
} |
|
|
|
KeyValues *CShaderDeviceMgrBase::ReadDXSupportKeyValues() |
|
{ |
|
if ( CommandLine()->CheckParm( "-ignoredxsupportcfg" ) ) |
|
return NULL; |
|
|
|
if ( m_pDXSupport ) |
|
return m_pDXSupport; |
|
|
|
KeyValues *pCfg = new KeyValues( "dxsupport" ); |
|
|
|
const char *pPathID = "EXECUTABLE_PATH"; |
|
if ( IsX360() && g_pFullFileSystem->GetDVDMode() == DVDMODE_STRICT ) |
|
{ |
|
// 360 dvd optimzation, expect it inside the platform zip |
|
pPathID = "PLATFORM"; |
|
} |
|
|
|
// First try to read a game-specific config, if it exists |
|
if ( !pCfg->LoadFromFile( g_pFullFileSystem, SUPPORT_CFG_FILE, pPathID ) ) |
|
{ |
|
pCfg->deleteThis(); |
|
return NULL; |
|
} |
|
|
|
char pTempPath[1024]; |
|
if ( g_pFullFileSystem->GetSearchPath( "GAME", false, pTempPath, sizeof(pTempPath) ) > 1 ) |
|
{ |
|
// Is there a mod-specific override file? |
|
KeyValues *pOverride = new KeyValues( "dxsupport_override" ); |
|
if ( pOverride->LoadFromFile( g_pFullFileSystem, SUPPORT_CFG_OVERRIDE_FILE, "GAME" ) ) |
|
{ |
|
OverrideKeyValues( pCfg, pOverride ); |
|
} |
|
|
|
pOverride->deleteThis(); |
|
} |
|
|
|
m_pDXSupport = pCfg; |
|
return pCfg; |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns the max dx support level achievable with this board |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceMgrBase::ReadDXSupportLevels( HardwareCaps_t &caps ) |
|
{ |
|
// See if the file tells us otherwise |
|
KeyValues *pCfg = ReadDXSupportKeyValues(); |
|
if ( !pCfg ) |
|
return; |
|
|
|
KeyValues *pDeviceKeyValues = FindCardSpecificConfig( pCfg, caps.m_VendorID, caps.m_DeviceID ); |
|
if ( pDeviceKeyValues ) |
|
{ |
|
// First, set the max dx level |
|
int nMaxDXSupportLevel = 0; |
|
ReadInt( pDeviceKeyValues, "MaxDXLevel", 0, &nMaxDXSupportLevel ); |
|
if ( nMaxDXSupportLevel != 0 ) |
|
{ |
|
caps.m_nMaxDXSupportLevel = nMaxDXSupportLevel; |
|
} |
|
|
|
// Next, set the preferred dx level |
|
int nDXSupportLevel = 0; |
|
ReadInt( pDeviceKeyValues, "DXLevel", 0, &nDXSupportLevel ); |
|
if ( nDXSupportLevel != 0 ) |
|
{ |
|
caps.m_nDXSupportLevel = nDXSupportLevel; |
|
// Don't slam up the dxlevel level to 92 on DX10 cards in OpenGL Linux/Win mode (otherwise Intel will get dxlevel 92 when we want 90) |
|
if ( !( IsOpenGL() && ( IsLinux() || IsWindows() ) ) ) |
|
{ |
|
if ( caps.m_bDX10Card ) |
|
{ |
|
caps.m_nDXSupportLevel = 92; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
caps.m_nDXSupportLevel = caps.m_nMaxDXSupportLevel; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Loads the hardware caps, for cases in which the D3D caps lie or where we need to augment the caps |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceMgrBase::LoadHardwareCaps( KeyValues *pGroup, HardwareCaps_t &caps ) |
|
{ |
|
if( !pGroup ) |
|
return; |
|
|
|
// don't just blanket kill clip planes on POSIX, only shoot them down if we're running ARB, or asked for nouserclipplanes. |
|
//FIXME need to take into account the caps bit that GLM can now provide, so NV can use normal clipping and ATI can fall back to fastclip. |
|
|
|
if ( CommandLine()->FindParm("-arbmode") || CommandLine()->CheckParm( "-nouserclip" ) ) |
|
{ |
|
caps.m_UseFastClipping = true; |
|
} |
|
else |
|
{ |
|
caps.m_UseFastClipping = ReadBool( pGroup, "NoUserClipPlanes", caps.m_UseFastClipping ); |
|
} |
|
|
|
caps.m_bNeedsATICentroidHack = ReadBool( pGroup, "CentroidHack", caps.m_bNeedsATICentroidHack ); |
|
caps.m_bDisableShaderOptimizations = ReadBool( pGroup, "DisableShaderOptimizations", caps.m_bDisableShaderOptimizations ); |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Reads in the hardware caps from the dxsupport.cfg file |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceMgrBase::ReadHardwareCaps( HardwareCaps_t &caps, int nDxLevel ) |
|
{ |
|
KeyValues *pCfg = ReadDXSupportKeyValues(); |
|
if ( !pCfg ) |
|
return; |
|
|
|
// Next, read the hardware caps for that dx support level. |
|
KeyValues *pDxLevelKeyValues = FindDXLevelSpecificConfig( pCfg, nDxLevel ); |
|
// Look for a vendor specific line for a given dxlevel. |
|
KeyValues *pDXLevelAndVendorKeyValue = FindDXLevelAndVendorSpecificConfig( pCfg, nDxLevel, caps.m_VendorID ); |
|
// Finally, override the hardware caps based on the specific card |
|
KeyValues *pCardKeyValues = FindCardSpecificConfig( pCfg, caps.m_VendorID, caps.m_DeviceID ); |
|
|
|
// Apply |
|
if( pCardKeyValues && ReadHexValue( pCardKeyValues, "MinDeviceID" ) == 0 && ReadHexValue( pCardKeyValues, "MaxDeviceID" ) == 0xffff ) |
|
{ |
|
// The card specific case is a catch all for device ids, so run it before running the dxlevel and card specific stuff. |
|
LoadHardwareCaps( pDxLevelKeyValues, caps ); |
|
LoadHardwareCaps( pCardKeyValues, caps ); |
|
LoadHardwareCaps( pDXLevelAndVendorKeyValue, caps ); |
|
} |
|
else |
|
{ |
|
// The card specific case is a small range of cards, so run it last to override all other configs. |
|
LoadHardwareCaps( pDxLevelKeyValues, caps ); |
|
// don't run this one since we have a specific config for this card. |
|
// LoadHardwareCaps( pDXLevelAndVendorKeyValue, caps ); |
|
LoadHardwareCaps( pCardKeyValues, caps ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Reads in ConVars + config variables |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceMgrBase::LoadConfig( KeyValues *pKeyValues, KeyValues *pConfiguration ) |
|
{ |
|
if( !pKeyValues ) |
|
return; |
|
|
|
if( CommandLine()->FindParm( "-debugdxsupport" ) ) |
|
{ |
|
CUtlBuffer tmpBuf; |
|
pKeyValues->RecursiveSaveToFile( tmpBuf, 0 ); |
|
Warning( "%s\n", ( const char * )tmpBuf.Base() ); |
|
} |
|
for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() ) |
|
{ |
|
AddKey( pConfiguration, pGroup ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Computes amount of ram |
|
//----------------------------------------------------------------------------- |
|
static unsigned long GetRam() |
|
{ |
|
MEMORYSTATUS stat; |
|
GlobalMemoryStatus( &stat ); |
|
|
|
char buf[256]; |
|
V_snprintf( buf, sizeof( buf ), "GlobalMemoryStatus: %llu\n", (uint64)(stat.dwTotalPhys) ); |
|
Plat_DebugString( buf ); |
|
|
|
return (stat.dwTotalPhys / (1024 * 1024)); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets the recommended configuration associated with a particular dx level |
|
//----------------------------------------------------------------------------- |
|
bool CShaderDeviceMgrBase::GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, int nVendorID, int nDeviceID, KeyValues *pConfiguration ) |
|
{ |
|
LOCK_SHADERAPI(); |
|
|
|
const HardwareCaps_t& caps = GetHardwareCaps( nAdapter ); |
|
if ( nDXLevel == 0 ) |
|
{ |
|
nDXLevel = caps.m_nDXSupportLevel; |
|
} |
|
nDXLevel = GetClosestActualDXLevel( nDXLevel ); |
|
if ( nDXLevel > caps.m_nMaxDXSupportLevel ) |
|
return false; |
|
|
|
KeyValues *pCfg = ReadDXSupportKeyValues(); |
|
if ( !pCfg ) |
|
return true; |
|
|
|
// Look for a dxlevel specific line |
|
KeyValues *pDxLevelKeyValues = FindDXLevelSpecificConfig( pCfg, nDXLevel ); |
|
// Look for a vendor specific line for a given dxlevel. |
|
KeyValues *pDXLevelAndVendorKeyValue = FindDXLevelAndVendorSpecificConfig( pCfg, nDXLevel, nVendorID ); |
|
// Next, override with device-specific overrides |
|
KeyValues *pCardKeyValues = FindCardSpecificConfig( pCfg, nVendorID, nDeviceID ); |
|
|
|
// Apply |
|
if ( pCardKeyValues && ReadHexValue( pCardKeyValues, "MinDeviceID" ) == 0 && ReadHexValue( pCardKeyValues, "MaxDeviceID" ) == 0xffff ) |
|
{ |
|
// The card specific case is a catch all for device ids, so run it before running the dxlevel and card specific stuff. |
|
LoadConfig( pDxLevelKeyValues, pConfiguration ); |
|
LoadConfig( pCardKeyValues, pConfiguration ); |
|
LoadConfig( pDXLevelAndVendorKeyValue, pConfiguration ); |
|
} |
|
else |
|
{ |
|
// The card specific case is a small range of cards, so run it last to override all other configs. |
|
LoadConfig( pDxLevelKeyValues, pConfiguration ); |
|
// don't run this one since we have a specific config for this card. |
|
// LoadConfig( pDXLevelAndVendorKeyValue, pConfiguration ); |
|
LoadConfig( pCardKeyValues, pConfiguration ); |
|
} |
|
|
|
// Next, override with cpu-speed based overrides |
|
const CPUInformation& pi = *GetCPUInformation(); |
|
int nCPUSpeedMhz = (int)(pi.m_Speed / 1000000.0f); |
|
|
|
bool bAMD = Q_stristr( pi.m_szProcessorID, "amd" ) != NULL; |
|
|
|
char buf[256]; |
|
V_snprintf( buf, sizeof( buf ), "CShaderDeviceMgrBase::GetRecommendedConfigurationInfo: CPU speed: %d MHz, Processor: %s\n", nCPUSpeedMhz, pi.m_szProcessorID ); |
|
Plat_DebugString( buf ); |
|
|
|
KeyValues *pCPUKeyValues = FindCPUSpecificConfig( pCfg, nCPUSpeedMhz, bAMD ); |
|
LoadConfig( pCPUKeyValues, pConfiguration ); |
|
|
|
// override with system memory-size based overrides |
|
int nSystemMB = GetRam(); |
|
DevMsg( "%d MB of system RAM\n", nSystemMB ); |
|
KeyValues *pMemoryKeyValues = FindMemorySpecificConfig( pCfg, nSystemMB ); |
|
LoadConfig( pMemoryKeyValues, pConfiguration ); |
|
|
|
// override with texture memory-size based overrides |
|
int nTextureMemorySize = GetVidMemBytes( nAdapter ); |
|
int vidMemMB = nTextureMemorySize / ( 1024 * 1024 ); |
|
KeyValues *pVidMemKeyValues = FindVidMemSpecificConfig( pCfg, vidMemMB ); |
|
if ( pVidMemKeyValues && nTextureMemorySize > 0 ) |
|
{ |
|
if ( CommandLine()->FindParm( "-debugdxsupport" ) ) |
|
{ |
|
CUtlBuffer tmpBuf; |
|
pVidMemKeyValues->RecursiveSaveToFile( tmpBuf, 0 ); |
|
Warning( "pVidMemKeyValues\n%s\n", ( const char * )tmpBuf.Base() ); |
|
} |
|
KeyValues *pMatPicmipKeyValue = pVidMemKeyValues->FindKey( "ConVar.mat_picmip", false ); |
|
|
|
// FIXME: Man, is this brutal. If it wasn't 1 day till orange box ship, I'd do something in dxsupport maybe |
|
if ( pMatPicmipKeyValue && ( ( nDXLevel == caps.m_nMaxDXSupportLevel ) || ( vidMemMB < 100 ) ) ) |
|
{ |
|
KeyValues *pConfigMatPicMip = pConfiguration->FindKey( "ConVar.mat_picmip", false ); |
|
int newPicMip = pMatPicmipKeyValue->GetInt(); |
|
int oldPicMip = pConfigMatPicMip ? pConfigMatPicMip->GetInt() : 0; |
|
pConfiguration->SetInt( "ConVar.mat_picmip", max( newPicMip, oldPicMip ) ); |
|
} |
|
} |
|
|
|
// Hack to slam the mat_dxlevel ConVar to match the requested dxlevel |
|
pConfiguration->SetInt( "ConVar.mat_dxlevel", nDXLevel ); |
|
|
|
if ( CommandLine()->FindParm( "-debugdxsupport" ) ) |
|
{ |
|
CUtlBuffer tmpBuf; |
|
pConfiguration->RecursiveSaveToFile( tmpBuf, 0 ); |
|
Warning( "final config:\n%s\n", ( const char * )tmpBuf.Base() ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets recommended congifuration for a particular adapter at a particular dx level |
|
//----------------------------------------------------------------------------- |
|
bool CShaderDeviceMgrBase::GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, KeyValues *pCongifuration ) |
|
{ |
|
Assert( nAdapter >= 0 && nAdapter <= GetAdapterCount() ); |
|
MaterialAdapterInfo_t info; |
|
GetAdapterInfo( nAdapter, info ); |
|
return GetRecommendedConfigurationInfo( nAdapter, nDXLevel, info.m_VendorID, info.m_DeviceID, pCongifuration ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns only valid dx levels |
|
//----------------------------------------------------------------------------- |
|
int CShaderDeviceMgrBase::GetClosestActualDXLevel( int nDxLevel ) const |
|
{ |
|
if ( nDxLevel < ABSOLUTE_MINIMUM_DXLEVEL ) |
|
return ABSOLUTE_MINIMUM_DXLEVEL; |
|
|
|
if ( nDxLevel == 80 ) |
|
return 80; |
|
if ( nDxLevel <= 89 ) |
|
return 81; |
|
|
|
if ( IsOpenGL() ) |
|
{ |
|
return ( nDxLevel <= 90 ) ? 90 : 92; |
|
} |
|
|
|
if ( nDxLevel <= 94 ) |
|
return 90; |
|
|
|
if ( IsX360() && nDxLevel <= 98 ) |
|
return 98; |
|
if ( nDxLevel <= 99 ) |
|
return 95; |
|
return 100; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Mode change callback |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceMgrBase::AddModeChangeCallback( ShaderModeChangeCallbackFunc_t func ) |
|
{ |
|
LOCK_SHADERAPI(); |
|
Assert( func && m_ModeChangeCallbacks.Find( func ) < 0 ); |
|
m_ModeChangeCallbacks.AddToTail( func ); |
|
} |
|
|
|
void CShaderDeviceMgrBase::RemoveModeChangeCallback( ShaderModeChangeCallbackFunc_t func ) |
|
{ |
|
LOCK_SHADERAPI(); |
|
m_ModeChangeCallbacks.FindAndRemove( func ); |
|
} |
|
|
|
void CShaderDeviceMgrBase::InvokeModeChangeCallbacks() |
|
{ |
|
int nCount = m_ModeChangeCallbacks.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
m_ModeChangeCallbacks[i](); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Factory to return from SetMode |
|
//----------------------------------------------------------------------------- |
|
void* CShaderDeviceMgrBase::ShaderInterfaceFactory( const char *pInterfaceName, int *pReturnCode ) |
|
{ |
|
if ( pReturnCode ) |
|
{ |
|
*pReturnCode = IFACE_OK; |
|
} |
|
if ( !Q_stricmp( pInterfaceName, SHADER_DEVICE_INTERFACE_VERSION ) ) |
|
return static_cast< IShaderDevice* >( g_pShaderDevice ); |
|
if ( !Q_stricmp( pInterfaceName, SHADERAPI_INTERFACE_VERSION ) ) |
|
return static_cast< IShaderAPI* >( g_pShaderAPI ); |
|
if ( !Q_stricmp( pInterfaceName, SHADERSHADOW_INTERFACE_VERSION ) ) |
|
return static_cast< IShaderShadow* >( g_pShaderShadow ); |
|
|
|
if ( pReturnCode ) |
|
{ |
|
*pReturnCode = IFACE_FAILED; |
|
} |
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// The Base implementation of the shader device |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// constructor, destructor |
|
//----------------------------------------------------------------------------- |
|
CShaderDeviceBase::CShaderDeviceBase() |
|
{ |
|
m_bInitialized = false; |
|
m_nAdapter = -1; |
|
m_hWnd = NULL; |
|
m_hWndCookie = NULL; |
|
m_dwThreadId = ThreadGetCurrentId(); |
|
} |
|
|
|
CShaderDeviceBase::~CShaderDeviceBase() |
|
{ |
|
} |
|
|
|
void CShaderDeviceBase::SetCurrentThreadAsOwner() |
|
{ |
|
m_dwThreadId = ThreadGetCurrentId(); |
|
} |
|
|
|
void CShaderDeviceBase::RemoveThreadOwner() |
|
{ |
|
m_dwThreadId = 0xFFFFFFFF; |
|
} |
|
|
|
bool CShaderDeviceBase::ThreadOwnsDevice() |
|
{ |
|
if ( ThreadGetCurrentId() == m_dwThreadId ) |
|
return true; |
|
return false; |
|
} |
|
|
|
|
|
// Methods of IShaderDevice |
|
ImageFormat CShaderDeviceBase::GetBackBufferFormat() const |
|
{ |
|
return IMAGE_FORMAT_UNKNOWN; |
|
} |
|
|
|
int CShaderDeviceBase::StencilBufferBits() const |
|
{ |
|
return 0; |
|
} |
|
|
|
bool CShaderDeviceBase::IsAAEnabled() const |
|
{ |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Methods for interprocess communication to release resources |
|
//----------------------------------------------------------------------------- |
|
#define MATERIAL_SYSTEM_WINDOW_ID 0xFEEDDEAD |
|
|
|
#ifdef USE_ACTUAL_DX |
|
static VD3DHWND GetTopmostParentWindow( VD3DHWND hWnd ) |
|
{ |
|
// Find the parent window... |
|
VD3DHWND hParent = GetParent( hWnd ); |
|
while ( hParent ) |
|
{ |
|
hWnd = hParent; |
|
hParent = GetParent( hWnd ); |
|
} |
|
|
|
return hWnd; |
|
} |
|
|
|
static BOOL CALLBACK EnumChildWindowsProc( VD3DHWND hWnd, LPARAM lParam ) |
|
{ |
|
int windowId = GetWindowLongPtr( hWnd, GWLP_USERDATA ); |
|
if (windowId == MATERIAL_SYSTEM_WINDOW_ID) |
|
{ |
|
COPYDATASTRUCT copyData; |
|
copyData.dwData = lParam; |
|
copyData.cbData = 0; |
|
copyData.lpData = 0; |
|
|
|
SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)©Data); |
|
} |
|
return TRUE; |
|
} |
|
|
|
static BOOL CALLBACK EnumWindowsProc( VD3DHWND hWnd, LPARAM lParam ) |
|
{ |
|
EnumChildWindows( hWnd, EnumChildWindowsProc, lParam ); |
|
return TRUE; |
|
} |
|
|
|
static BOOL CALLBACK EnumWindowsProcNotThis( VD3DHWND hWnd, LPARAM lParam ) |
|
{ |
|
if ( g_pShaderDevice && ( GetTopmostParentWindow( (VD3DHWND)g_pShaderDevice->GetIPCHWnd() ) == hWnd ) ) |
|
return TRUE; |
|
|
|
EnumChildWindows( hWnd, EnumChildWindowsProc, lParam ); |
|
return TRUE; |
|
} |
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Adds a hook to let us know when other instances are setting the mode |
|
//----------------------------------------------------------------------------- |
|
|
|
#ifdef STRICT |
|
#define WINDOW_PROC WNDPROC |
|
#else |
|
#define WINDOW_PROC FARPROC |
|
#endif |
|
|
|
#ifdef USE_ACTUAL_DX |
|
static LRESULT CALLBACK ShaderDX8WndProc(VD3DHWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
#if !defined( _X360 ) |
|
// FIXME: Should these IPC messages tell when an app has focus or not? |
|
// If so, we'd want to totally disable the shader api layer when an app |
|
// doesn't have focus. |
|
|
|
// Look for the special IPC message that tells us we're trying to set |
|
// the mode.... |
|
switch(msg) |
|
{ |
|
case WM_COPYDATA: |
|
{ |
|
if ( !g_pShaderDevice ) |
|
break; |
|
|
|
COPYDATASTRUCT* pData = (COPYDATASTRUCT*)lParam; |
|
|
|
// that number is our magic cookie number |
|
if ( pData->dwData == CShaderDeviceBase::RELEASE_MESSAGE ) |
|
{ |
|
g_pShaderDevice->OtherAppInitializing(true); |
|
} |
|
else if ( pData->dwData == CShaderDeviceBase::REACQUIRE_MESSAGE ) |
|
{ |
|
g_pShaderDevice->OtherAppInitializing(false); |
|
} |
|
else if ( pData->dwData == CShaderDeviceBase::EVICT_MESSAGE ) |
|
{ |
|
g_pShaderDevice->EvictManagedResourcesInternal( ); |
|
} |
|
} |
|
break; |
|
} |
|
|
|
return DefWindowProc( hWnd, msg, wParam, lParam ); |
|
#endif |
|
} |
|
#endif |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Install, remove ability to talk to other shaderapi apps |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceBase::InstallWindowHook( void* hWnd ) |
|
{ |
|
Assert( m_hWndCookie == NULL ); |
|
#ifdef USE_ACTUAL_DX |
|
#if !defined( _X360 ) |
|
VD3DHWND hParent = GetTopmostParentWindow( (VD3DHWND)hWnd ); |
|
|
|
// Attach a child window to the parent; we're gonna store special info there |
|
// We can't use the USERDATA, cause other apps may want to use this. |
|
HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr( hParent, GWLP_HINSTANCE ); |
|
WNDCLASS wc; |
|
memset( &wc, 0, sizeof( wc ) ); |
|
wc.style = CS_NOCLOSE | CS_PARENTDC; |
|
wc.lpfnWndProc = ShaderDX8WndProc; |
|
wc.hInstance = hInst; |
|
wc.lpszClassName = "shaderdx8"; |
|
|
|
// In case an old one is sitting around still... |
|
UnregisterClass( "shaderdx8", hInst ); |
|
|
|
RegisterClass( &wc ); |
|
|
|
// Create the window |
|
m_hWndCookie = CreateWindow( "shaderdx8", "shaderdx8", WS_CHILD, |
|
0, 0, 0, 0, hParent, NULL, hInst, NULL ); |
|
|
|
// Marks it as a material system window |
|
SetWindowLongPtr( (VD3DHWND)m_hWndCookie, GWLP_USERDATA, MATERIAL_SYSTEM_WINDOW_ID ); |
|
#endif |
|
#endif |
|
} |
|
|
|
void CShaderDeviceBase::RemoveWindowHook( void* hWnd ) |
|
{ |
|
#ifdef USE_ACTUAL_DX |
|
#if !defined( _X360 ) |
|
if ( m_hWndCookie ) |
|
{ |
|
DestroyWindow( (VD3DHWND)m_hWndCookie ); |
|
m_hWndCookie = 0; |
|
} |
|
|
|
VD3DHWND hParent = GetTopmostParentWindow( (VD3DHWND)hWnd ); |
|
HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr( hParent, GWLP_HINSTANCE ); |
|
UnregisterClass( "shaderdx8", hInst ); |
|
#endif |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sends a message to other shaderapi applications |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceBase::SendIPCMessage( IPCMessage_t msg ) |
|
{ |
|
#ifdef USE_ACTUAL_DX |
|
#if !defined( _X360 ) |
|
// Gotta send this to all windows, since we don't know which ones |
|
// are material system apps... |
|
if ( msg != EVICT_MESSAGE ) |
|
{ |
|
EnumWindows( EnumWindowsProc, (DWORD)msg ); |
|
} |
|
else |
|
{ |
|
EnumWindows( EnumWindowsProcNotThis, (DWORD)msg ); |
|
} |
|
#endif |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Find view |
|
//----------------------------------------------------------------------------- |
|
int CShaderDeviceBase::FindView( void* hWnd ) const |
|
{ |
|
/* FIXME: Is this necessary? |
|
// Look for the view in the list of views |
|
for (int i = m_Views.Count(); --i >= 0; ) |
|
{ |
|
if (m_Views[i].m_HWnd == (VD3DHWND)hwnd) |
|
return i; |
|
} |
|
*/ |
|
return -1; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Creates a child window |
|
//----------------------------------------------------------------------------- |
|
bool CShaderDeviceBase::AddView( void* hWnd ) |
|
{ |
|
LOCK_SHADERAPI(); |
|
/* |
|
// If we haven't created a device yet |
|
if (!Dx9Device()) |
|
return false; |
|
|
|
// Make sure no duplicate hwnds... |
|
if (FindView(hwnd) >= 0) |
|
return false; |
|
|
|
// In this case, we need to create the device; this is our |
|
// default swap chain. This here says we're gonna use a part of the |
|
// existing buffer and just grab that. |
|
int view = m_Views.AddToTail(); |
|
m_Views[view].m_HWnd = (VD3DHWND)hwnd; |
|
// memcpy( &m_Views[view].m_PresentParamters, m_PresentParameters, sizeof(m_PresentParamters) ); |
|
|
|
HRESULT hr; |
|
hr = Dx9Device()->CreateAdditionalSwapChain( &m_PresentParameters, |
|
&m_Views[view].m_pSwapChain ); |
|
return !FAILED(hr); |
|
*/ |
|
|
|
return true; |
|
} |
|
|
|
void CShaderDeviceBase::RemoveView( void* hWnd ) |
|
{ |
|
LOCK_SHADERAPI(); |
|
/* |
|
// Look for the view in the list of views |
|
int i = FindView(hwnd); |
|
if (i >= 0) |
|
{ |
|
// FIXME m_Views[i].m_pSwapChain->Release(); |
|
m_Views.FastRemove(i); |
|
} |
|
*/ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Activates a child window |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceBase::SetView( void* hWnd ) |
|
{ |
|
LOCK_SHADERAPI(); |
|
|
|
ShaderViewport_t viewport; |
|
g_pShaderAPI->GetViewports( &viewport, 1 ); |
|
|
|
// Get the window (*not* client) rect of the view window |
|
m_ViewHWnd = (VD3DHWND)hWnd; |
|
GetWindowSize( m_nWindowWidth, m_nWindowHeight ); |
|
|
|
// Reset the viewport (takes into account the view rect) |
|
// Don't need to set the viewport if it's not ready |
|
g_pShaderAPI->SetViewports( 1, &viewport ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets the window size |
|
//----------------------------------------------------------------------------- |
|
void CShaderDeviceBase::GetWindowSize( int& nWidth, int& nHeight ) const |
|
{ |
|
#if defined( USE_SDL ) |
|
|
|
// this matches up to what the threaded material system does |
|
g_pShaderAPI->GetBackBufferDimensions( nWidth, nHeight ); |
|
|
|
#else |
|
|
|
// If the window was minimized last time swap buffers happened, or if it's iconic now, |
|
// return 0 size |
|
#ifdef _WIN32 |
|
if ( !m_bIsMinimized && !IsIconic( ( HWND )m_hWnd ) ) |
|
#else |
|
if ( !m_bIsMinimized && !IsIconic( (VD3DHWND)m_hWnd ) ) |
|
#endif |
|
{ |
|
// NOTE: Use the 'current view' (which may be the same as the main window) |
|
RECT rect; |
|
#ifdef _WIN32 |
|
GetClientRect( ( HWND )m_ViewHWnd, &rect ); |
|
#else |
|
toglGetClientRect( (VD3DHWND)m_ViewHWnd, &rect ); |
|
#endif |
|
nWidth = rect.right - rect.left; |
|
nHeight = rect.bottom - rect.top; |
|
} |
|
else |
|
{ |
|
nWidth = nHeight = 0; |
|
} |
|
|
|
#endif |
|
} |
|
|
|
|
|
|