Counter Strike : Global Offensive Source Code
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.

1235 lines
37 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #define DISABLE_PROTECTED_THINGS
  9. #include "togl/rendermechanism.h"
  10. #include "shaderdevicebase.h"
  11. #include "tier1/keyvalues.h"
  12. #include "tier1/convar.h"
  13. #include "tier1/utlbuffer.h"
  14. #include "tier0/icommandline.h"
  15. #include "tier2/tier2.h"
  16. #include "filesystem.h"
  17. #include "datacache/idatacache.h"
  18. #include "shaderapi/ishaderutil.h"
  19. #include "shaderapibase.h"
  20. #include "shaderapi/ishadershadow.h"
  21. #include "shaderapi_global.h"
  22. #include "videocfg/videocfg.h"
  23. #include "vjobs_interface.h"
  24. #include "winutils.h"
  25. #ifdef _X360
  26. #include "xbox/xbox_win32stubs.h"
  27. #endif
  28. // NOTE: This has to be the last file included!
  29. #include "tier0/memdbgon.h"
  30. //-----------------------------------------------------------------------------
  31. // Globals
  32. //-----------------------------------------------------------------------------
  33. CShaderDeviceBase *g_pShaderDevice;
  34. CShaderAPIBase *g_pShaderAPI;
  35. CShaderDeviceMgrBase *g_pShaderDeviceMgr;
  36. IShaderShadow *g_pShaderShadow;
  37. #if !defined( _PS3 ) && !defined( _OSX )
  38. IShaderUtil* g_pShaderUtil; // The main shader utility interface
  39. IVJobs * g_pVJobs;
  40. #else
  41. extern IVJobs * g_pVJobs;
  42. #endif
  43. bool g_bUseShaderMutex = false; // Shader mutex globals
  44. bool g_bShaderAccessDisallowed;
  45. CShaderMutex g_ShaderMutex;
  46. //-----------------------------------------------------------------------------
  47. // FIXME: Hack related to setting command-line values for convars. Remove!!!
  48. //-----------------------------------------------------------------------------
  49. class CShaderAPIConVarAccessor : public IConCommandBaseAccessor
  50. {
  51. public:
  52. virtual bool RegisterConCommandBase( ConCommandBase *pCommand )
  53. {
  54. // Link to engine's list instead
  55. g_pCVar->RegisterConCommand( pCommand );
  56. char const *pValue = g_pCVar->GetCommandLineValue( pCommand->GetName() );
  57. if( pValue && !pCommand->IsCommand() )
  58. {
  59. ( ( ConVar * )pCommand )->SetValue( pValue );
  60. }
  61. return true;
  62. }
  63. };
  64. static void InitShaderAPICVars( )
  65. {
  66. static CShaderAPIConVarAccessor g_ConVarAccessor;
  67. if ( g_pCVar )
  68. {
  69. ConVar_Register( FCVAR_MATERIAL_SYSTEM_THREAD, &g_ConVarAccessor );
  70. }
  71. }
  72. //-----------------------------------------------------------------------------
  73. // Read dx support levels
  74. //-----------------------------------------------------------------------------
  75. #if defined( PLATFORM_POSIX ) && !defined( _PS3 )
  76. #define SUPPORT_CFG_FILE "dxsupport_mac.cfg"
  77. // TODO: make this different for Mac?
  78. #define SUPPORT_CFG_OVERRIDE_FILE "dxsupport_override.cfg"
  79. #else
  80. #define SUPPORT_CFG_FILE "dxsupport.cfg"
  81. #define SUPPORT_CFG_OVERRIDE_FILE "dxsupport_override.cfg"
  82. #endif
  83. //-----------------------------------------------------------------------------
  84. // constructor, destructor
  85. //-----------------------------------------------------------------------------
  86. CShaderDeviceMgrBase::CShaderDeviceMgrBase()
  87. {
  88. m_pDXSupport = NULL;
  89. #if defined( _PS3 ) || defined( _OSX )
  90. g_pShaderDeviceMgr = this;
  91. #endif
  92. }
  93. CShaderDeviceMgrBase::~CShaderDeviceMgrBase()
  94. {
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Factory used to get at internal interfaces (used by shaderapi + shader dlls)
  98. //-----------------------------------------------------------------------------
  99. static CreateInterfaceFn s_TempFactory;
  100. void *ShaderDeviceFactory( const char *pName, int *pReturnCode )
  101. {
  102. if (pReturnCode)
  103. {
  104. *pReturnCode = IFACE_OK;
  105. }
  106. void *pInterface = s_TempFactory( pName, pReturnCode );
  107. if ( pInterface )
  108. return pInterface;
  109. pInterface = Sys_GetFactoryThis()( pName, pReturnCode );
  110. if ( pInterface )
  111. return pInterface;
  112. if ( pReturnCode )
  113. {
  114. *pReturnCode = IFACE_FAILED;
  115. }
  116. return NULL;
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Connect, disconnect
  120. //-----------------------------------------------------------------------------
  121. bool CShaderDeviceMgrBase::Connect( CreateInterfaceFn factory )
  122. {
  123. LOCK_SHADERAPI();
  124. Assert( IsPS3() || IsOSX() || !g_pShaderDeviceMgr );
  125. s_TempFactory = factory;
  126. // Connection/convar registration
  127. CreateInterfaceFn actualFactory = ShaderDeviceFactory;
  128. ConnectTier1Libraries( &actualFactory, 1 );
  129. InitShaderAPICVars();
  130. ConnectTier2Libraries( &actualFactory, 1 );
  131. #if !defined( _PS3 ) && !defined( _OSX )
  132. if ( !g_pShaderUtil )
  133. g_pShaderUtil = (IShaderUtil*)ShaderDeviceFactory( SHADER_UTIL_INTERFACE_VERSION, NULL );
  134. #endif
  135. if ( !g_pVJobs )
  136. g_pVJobs = (IVJobs *)ShaderDeviceFactory( VJOBS_INTERFACE_VERSION, NULL );
  137. g_pShaderDeviceMgr = this;
  138. s_TempFactory = NULL;
  139. if ( !g_pShaderUtil || !g_pFullFileSystem || !g_pShaderDeviceMgr )
  140. {
  141. Warning( "ShaderAPIDx10 was unable to access the required interfaces!\n" );
  142. return false;
  143. }
  144. // NOTE! : Overbright is 1.0 so that Hammer will work properly with the white bumped and unbumped lightmaps.
  145. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
  146. return true;
  147. }
  148. void CShaderDeviceMgrBase::Disconnect()
  149. {
  150. LOCK_SHADERAPI();
  151. #if !defined( _PS3 ) && !defined( _OSX )
  152. g_pShaderDeviceMgr = NULL;
  153. g_pShaderUtil = NULL;
  154. #endif
  155. DisconnectTier2Libraries();
  156. ConVar_Unregister();
  157. DisconnectTier1Libraries();
  158. if ( m_pDXSupport )
  159. {
  160. m_pDXSupport->deleteThis();
  161. m_pDXSupport = NULL;
  162. }
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Query interface
  166. //-----------------------------------------------------------------------------
  167. void *CShaderDeviceMgrBase::QueryInterface( const char *pInterfaceName )
  168. {
  169. if ( !Q_stricmp( pInterfaceName, SHADER_DEVICE_MGR_INTERFACE_VERSION ) )
  170. return ( IShaderDeviceMgr* )this;
  171. if ( !Q_stricmp( pInterfaceName, MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION ) )
  172. return ( IMaterialSystemHardwareConfig* )g_pHardwareConfig;
  173. return NULL;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Returns the hardware caps for a particular adapter
  177. //-----------------------------------------------------------------------------
  178. const HardwareCaps_t& CShaderDeviceMgrBase::GetHardwareCaps( int nAdapter ) const
  179. {
  180. Assert( ( nAdapter >= 0 ) && ( nAdapter < GetAdapterCount() ) );
  181. return m_Adapters[nAdapter].m_ActualCaps;
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Utility methods for reading config scripts
  185. //-----------------------------------------------------------------------------
  186. static inline int ReadHexValue( KeyValues *pVal, const char *pName )
  187. {
  188. const char *pString = pVal->GetString( pName, NULL );
  189. if (!pString)
  190. {
  191. return -1;
  192. }
  193. char *pTemp;
  194. int nVal = strtol( pString, &pTemp, 16 );
  195. return (pTemp != pString) ? nVal : -1;
  196. }
  197. static bool ReadBool( KeyValues *pGroup, const char *pKeyName, bool bDefault )
  198. {
  199. int nVal = pGroup->GetInt( pKeyName, -1 );
  200. if ( nVal != -1 )
  201. {
  202. // Warning( "\t%s = %s\n", pKeyName, (nVal != false) ? "true" : "false" );
  203. return (nVal != false);
  204. }
  205. return bDefault;
  206. }
  207. static void ReadInt( KeyValues *pGroup, const char *pKeyName, int nInvalidValue, int *pResult )
  208. {
  209. int nVal = pGroup->GetInt( pKeyName, nInvalidValue );
  210. if ( nVal != nInvalidValue )
  211. {
  212. *pResult = nVal;
  213. // Warning( "\t%s = %d\n", pKeyName, *pResult );
  214. }
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Utility method to copy over a keyvalue
  218. //-----------------------------------------------------------------------------
  219. static void AddKey( KeyValues *pDest, KeyValues *pSrc )
  220. {
  221. // Note this will replace already-existing values
  222. switch( pSrc->GetDataType() )
  223. {
  224. case KeyValues::TYPE_NONE:
  225. break;
  226. case KeyValues::TYPE_STRING:
  227. pDest->SetString( pSrc->GetName(), pSrc->GetString() );
  228. break;
  229. case KeyValues::TYPE_INT:
  230. pDest->SetInt( pSrc->GetName(), pSrc->GetInt() );
  231. break;
  232. case KeyValues::TYPE_FLOAT:
  233. pDest->SetFloat( pSrc->GetName(), pSrc->GetFloat() );
  234. break;
  235. case KeyValues::TYPE_PTR:
  236. pDest->SetPtr( pSrc->GetName(), pSrc->GetPtr() );
  237. break;
  238. case KeyValues::TYPE_WSTRING:
  239. pDest->SetWString( pSrc->GetName(), pSrc->GetWString() );
  240. break;
  241. case KeyValues::TYPE_COLOR:
  242. pDest->SetColor( pSrc->GetName(), pSrc->GetColor() );
  243. break;
  244. default:
  245. Assert( 0 );
  246. break;
  247. }
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Finds if we have a dxlevel-specific config in the support keyvalues
  251. //-----------------------------------------------------------------------------
  252. KeyValues *CShaderDeviceMgrBase::FindDXLevelSpecificConfig( KeyValues *pKeyValues, int nDxLevel )
  253. {
  254. KeyValues *pGroup = pKeyValues->GetFirstSubKey();
  255. for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
  256. {
  257. int nFoundDxLevel = pGroup->GetInt( "name", 0 );
  258. if( nFoundDxLevel == nDxLevel )
  259. return pGroup;
  260. }
  261. return NULL;
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Finds if we have a dxlevel and vendor-specific config in the support keyvalues
  265. //-----------------------------------------------------------------------------
  266. KeyValues *CShaderDeviceMgrBase::FindDXLevelAndVendorSpecificConfig( KeyValues *pKeyValues, int nDxLevel, int nVendorID )
  267. {
  268. if ( IsX360() )
  269. {
  270. // 360 unique dxlevel implies hw config, vendor variance not applicable
  271. return NULL;
  272. }
  273. KeyValues *pGroup = pKeyValues->GetFirstSubKey();
  274. for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
  275. {
  276. int nFoundDxLevel = pGroup->GetInt( "name", 0 );
  277. int nFoundVendorID = ReadHexValue( pGroup, "VendorID" );
  278. if( nFoundDxLevel == nDxLevel && nFoundVendorID == nVendorID )
  279. return pGroup;
  280. }
  281. return NULL;
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Finds if we have a vendor-specific config in the support keyvalues
  285. //-----------------------------------------------------------------------------
  286. KeyValues *CShaderDeviceMgrBase::FindCPUSpecificConfig( KeyValues *pKeyValues, int nCPUMhz, bool bAMD )
  287. {
  288. if ( IsX360() )
  289. {
  290. // 360 unique dxlevel implies hw config, cpu variance not applicable
  291. return NULL;
  292. }
  293. for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
  294. {
  295. const char *pName = pGroup->GetString( "name", NULL );
  296. if ( !pName )
  297. continue;
  298. if ( ( bAMD && Q_stristr( pName, "AMD" ) ) ||
  299. ( !bAMD && Q_stristr( pName, "Intel" ) ) )
  300. {
  301. int nMinMegahertz = pGroup->GetInt( "min megahertz", -1 );
  302. int nMaxMegahertz = pGroup->GetInt( "max megahertz", -1 );
  303. if( nMinMegahertz == -1 || nMaxMegahertz == -1 )
  304. continue;
  305. if( nMinMegahertz <= nCPUMhz && nCPUMhz < nMaxMegahertz )
  306. return pGroup;
  307. }
  308. }
  309. return NULL;
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Finds if we have a vendor-specific config in the support keyvalues
  313. //-----------------------------------------------------------------------------
  314. KeyValues *CShaderDeviceMgrBase::FindCardSpecificConfig( KeyValues *pKeyValues, int nVendorId, int nDeviceId )
  315. {
  316. if ( IsX360() )
  317. {
  318. // 360 unique dxlevel implies hw config, vendor variance not applicable
  319. return NULL;
  320. }
  321. KeyValues *pGroup = pKeyValues->GetFirstSubKey();
  322. for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
  323. {
  324. int nFoundVendorId = ReadHexValue( pGroup, "VendorID" );
  325. int nFoundDeviceIdMin = ReadHexValue( pGroup, "MinDeviceID" );
  326. int nFoundDeviceIdMax = ReadHexValue( pGroup, "MaxDeviceID" );
  327. if ( nFoundVendorId == nVendorId && nDeviceId >= nFoundDeviceIdMin && nDeviceId <= nFoundDeviceIdMax )
  328. return pGroup;
  329. }
  330. return NULL;
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Finds if we have a vendor-specific config in the support keyvalues
  334. //-----------------------------------------------------------------------------
  335. KeyValues *CShaderDeviceMgrBase::FindMemorySpecificConfig( KeyValues *pKeyValues, int nSystemRamMB )
  336. {
  337. if ( IsX360() )
  338. {
  339. // 360 unique dxlevel implies hw config, memory variance not applicable
  340. return NULL;
  341. }
  342. for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
  343. {
  344. // Used to help us debug this code
  345. // const char *pDebugName = pGroup->GetString( "name", "blah" );
  346. int nMinMB = pGroup->GetInt( "min megabytes", -1 );
  347. int nMaxMB = pGroup->GetInt( "max megabytes", -1 );
  348. if ( nMinMB == -1 || nMaxMB == -1 )
  349. continue;
  350. if ( nMinMB <= nSystemRamMB && nSystemRamMB < nMaxMB )
  351. return pGroup;
  352. }
  353. return NULL;
  354. }
  355. //-----------------------------------------------------------------------------
  356. // Finds if we have a texture mem size specific config
  357. //-----------------------------------------------------------------------------
  358. KeyValues *CShaderDeviceMgrBase::FindVidMemSpecificConfig( KeyValues *pKeyValues, int nVideoRamMB )
  359. {
  360. if ( IsX360() )
  361. {
  362. // 360 unique dxlevel implies hw config, vidmem variance not applicable
  363. return NULL;
  364. }
  365. for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
  366. {
  367. int nMinMB = pGroup->GetInt( "min megatexels", -1 );
  368. int nMaxMB = pGroup->GetInt( "max megatexels", -1 );
  369. if ( nMinMB == -1 || nMaxMB == -1 )
  370. continue;
  371. if ( nMinMB <= nVideoRamMB && nVideoRamMB < nMaxMB )
  372. return pGroup;
  373. }
  374. return NULL;
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Methods related to reading DX support levels given particular devices
  378. //-----------------------------------------------------------------------------
  379. KeyValues *CShaderDeviceMgrBase::ReadDXSupportKeyValues()
  380. {
  381. if ( CommandLine()->CheckParm( "-ignoredxsupportcfg" ) )
  382. return NULL;
  383. if ( m_pDXSupport )
  384. return m_pDXSupport;
  385. KeyValues *pCfg = new KeyValues( "dxsupport" );
  386. const char *pPathID = "EXECUTABLE_PATH";
  387. if ( IsX360() && g_pFullFileSystem->GetDVDMode() != DVDMODE_OFF )
  388. {
  389. // 360 dvd optimization, expect it inside the platform zip
  390. pPathID = "PLATFORM";
  391. }
  392. // First try to read a game-specific config, if it exists
  393. if ( !pCfg->LoadFromFile( g_pFullFileSystem, SUPPORT_CFG_FILE, pPathID ) )
  394. {
  395. pCfg->deleteThis();
  396. return NULL;
  397. }
  398. m_pDXSupport = pCfg;
  399. return pCfg;
  400. }
  401. //-----------------------------------------------------------------------------
  402. // Returns the max dx support level achievable with this board
  403. //-----------------------------------------------------------------------------
  404. void CShaderDeviceMgrBase::ReadDXSupportLevels( HardwareCaps_t &caps )
  405. {
  406. // See if the file tells us otherwise
  407. KeyValues *pCfg = ReadDXSupportKeyValues();
  408. if ( !pCfg )
  409. return;
  410. KeyValues *pDeviceKeyValues = FindCardSpecificConfig( pCfg, caps.m_VendorID, caps.m_DeviceID );
  411. if ( pDeviceKeyValues )
  412. {
  413. // First, set the max dx level
  414. int nMaxDXSupportLevel = 0;
  415. ReadInt( pDeviceKeyValues, "setting.MaxDXLevel", 0, &nMaxDXSupportLevel );
  416. if ( nMaxDXSupportLevel != 0 )
  417. {
  418. caps.m_nMaxDXSupportLevel = nMaxDXSupportLevel;
  419. }
  420. int nMinDXSupportLevel = 0;
  421. ReadInt( pDeviceKeyValues, "setting.MinDXLevel", 0, &nMinDXSupportLevel );
  422. if ( nMinDXSupportLevel != 0 && nMinDXSupportLevel <= caps.m_nMaxDXSupportLevel )
  423. {
  424. caps.m_nMinDXSupportLevel = nMinDXSupportLevel;
  425. }
  426. // Next, set the preferred dx level
  427. int nDXSupportLevel = 0;
  428. ReadInt( pDeviceKeyValues, "setting.DXLevel", 0, &nDXSupportLevel );
  429. if ( nDXSupportLevel != 0 )
  430. {
  431. caps.m_nDXSupportLevel = nDXSupportLevel;
  432. }
  433. else
  434. {
  435. caps.m_nDXSupportLevel = caps.m_nMaxDXSupportLevel;
  436. }
  437. }
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Loads the hardware caps, for cases in which the D3D caps lie or where we need to augment the caps
  441. //-----------------------------------------------------------------------------
  442. #ifdef OSX
  443. ConVar mat_osx_csm_enabled( "mat_osx_csm_enabled", "1", FCVAR_DEVELOPMENTONLY, "" );
  444. #endif
  445. void CShaderDeviceMgrBase::LoadHardwareCaps( KeyValues *pGroup, HardwareCaps_t &caps )
  446. {
  447. if( !pGroup )
  448. return;
  449. #ifndef _PS3
  450. // don't just blanket kill clip planes on POSIX, only shoot them down if we're running ARB, or asked for nouserclipplanes.
  451. //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.
  452. if ( CommandLine()->FindParm("-arbmode") || CommandLine()->CheckParm( "-nouserclip" ) )
  453. {
  454. caps.m_UseFastClipping = true;
  455. }
  456. else
  457. {
  458. caps.m_UseFastClipping = ReadBool( pGroup, "setting.NoUserClipPlanes", caps.m_UseFastClipping );
  459. }
  460. #endif
  461. caps.m_bNeedsATICentroidHack = ReadBool( pGroup, "setting.CentroidHack", caps.m_bNeedsATICentroidHack );
  462. caps.m_bDisableShaderOptimizations = ReadBool( pGroup, "setting.DisableShaderOptimizations", caps.m_bDisableShaderOptimizations );
  463. caps.m_bPreferZPrepass = ReadBool( pGroup, "setting.PreferZPrepass", caps.m_bPreferZPrepass );
  464. caps.m_bSuppressPixelShaderCentroidHackFixup = ReadBool( pGroup, "setting.SuppressPixelShaderCentroidHackFixup", caps.m_bSuppressPixelShaderCentroidHackFixup );
  465. caps.m_bPreferTexturesInHWMemory = ReadBool( pGroup, "setting.PreferTexturesInHWMemory", caps.m_bPreferTexturesInHWMemory );
  466. caps.m_bPreferHardwareSync = ReadBool( pGroup, "setting.PreferHardwareSync", caps.m_bPreferHardwareSync );
  467. caps.m_bUnsupported = ReadBool( pGroup, "setting.Unsupported", caps.m_bUnsupported );
  468. // dxsupport can only kill CSM support, not forcefully enable it.
  469. if ( !ReadBool( pGroup, "setting.SupportsCascadedShadowMapping", true ) )
  470. {
  471. #ifdef OSX
  472. // Set convar mat_osx_csm_enabled to 0 and do not touch caps.m_bSupportsCascadedShadowMapping (as CS:GO always had
  473. // the caps set to true, therefore code path where the caps is false haven't been tested and might not be safe)
  474. mat_osx_csm_enabled.SetValue( 0 );
  475. #else
  476. caps.m_bSupportsCascadedShadowMapping = false;
  477. #endif
  478. }
  479. int nCSMQuality = CSMQUALITY_VERY_LOW;
  480. ReadInt( pGroup, "setting.CSMQuality", 0, &nCSMQuality );
  481. caps.m_nCSMQuality = static_cast<uint8>( clamp( nCSMQuality, 0, CSMQUALITY_TOTAL_MODES - 1 ) );
  482. }
  483. //-----------------------------------------------------------------------------
  484. // Reads in the hardware caps from the dxsupport.cfg file
  485. //-----------------------------------------------------------------------------
  486. void CShaderDeviceMgrBase::ReadHardwareCaps( HardwareCaps_t &caps, int nDxLevel )
  487. {
  488. KeyValues *pCfg = ReadDXSupportKeyValues();
  489. if ( !pCfg )
  490. return;
  491. // Next, read the hardware caps for that dx support level.
  492. KeyValues *pDxLevelKeyValues = FindDXLevelSpecificConfig( pCfg, nDxLevel );
  493. // Look for a vendor specific line for a given dxlevel.
  494. KeyValues *pDXLevelAndVendorKeyValue = FindDXLevelAndVendorSpecificConfig( pCfg, nDxLevel, caps.m_VendorID );
  495. // Finally, override the hardware caps based on the specific card
  496. KeyValues *pCardKeyValues = FindCardSpecificConfig( pCfg, caps.m_VendorID, caps.m_DeviceID );
  497. // Apply
  498. if( pCardKeyValues && ReadHexValue( pCardKeyValues, "MinDeviceID" ) == 0 && ReadHexValue( pCardKeyValues, "MaxDeviceID" ) == 0xffff )
  499. {
  500. // The card specific case is a catch all for device ids, so run it before running the dxlevel and card specific stuff.
  501. LoadHardwareCaps( pDxLevelKeyValues, caps );
  502. LoadHardwareCaps( pCardKeyValues, caps );
  503. LoadHardwareCaps( pDXLevelAndVendorKeyValue, caps );
  504. }
  505. else
  506. {
  507. // The card specific case is a small range of cards, so run it last to override all other configs.
  508. LoadHardwareCaps( pDxLevelKeyValues, caps );
  509. // don't run this one since we have a specific config for this card.
  510. // LoadHardwareCaps( pDXLevelAndVendorKeyValue, caps );
  511. LoadHardwareCaps( pCardKeyValues, caps );
  512. }
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Reads in ConVars + config variables
  516. //-----------------------------------------------------------------------------
  517. void CShaderDeviceMgrBase::LoadConfig( KeyValues *pKeyValues, KeyValues *pConfiguration )
  518. {
  519. if( !pKeyValues )
  520. return;
  521. if( CommandLine()->FindParm( "-debugdxsupport" ) )
  522. {
  523. CUtlBuffer tmpBuf;
  524. pKeyValues->RecursiveSaveToFile( tmpBuf, 0 );
  525. Warning( "%s\n", ( const char * )tmpBuf.Base() );
  526. }
  527. for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
  528. {
  529. AddKey( pConfiguration, pGroup );
  530. }
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Computes amount of ram
  534. //-----------------------------------------------------------------------------
  535. static unsigned long GetRam()
  536. {
  537. #if defined(PLATFORM_WINDOWS)
  538. MEMORYSTATUSEX statex;
  539. statex.dwLength = sizeof( MEMORYSTATUSEX );
  540. GlobalMemoryStatusEx( &statex );
  541. if ( statex.ullAvailPhys < statex.ullAvailVirtual )
  542. {
  543. return ( unsigned long )( statex.ullAvailPhys / ( 1024 * 1024 ) );
  544. }
  545. return ( unsigned long )( statex.ullAvailVirtual / ( 1024 * 1024 ) );
  546. #else
  547. MEMORYSTATUS stat;
  548. stat.dwLength = sizeof( MEMORYSTATUS );
  549. GlobalMemoryStatus( &stat );
  550. return ( unsigned long )( stat.dwTotalPhys / ( 1024 * 1024 ) );
  551. #endif
  552. }
  553. //-----------------------------------------------------------------------------
  554. // Purpose: Gets the recommended video configuration.
  555. // Called from:
  556. // 1. Called from gameui.dll->OptionsSubVideo.cpp->COptionsSubVideoAdvancedDlg to fill in the video options panel.
  557. // 2. Called from gameui.dll->OptionsSubVideo.cpp->MarkDefaultSettingsAsRecommended when action is "Reset To Defaults"
  558. //-----------------------------------------------------------------------------
  559. bool CShaderDeviceMgrBase::GetRecommendedVideoConfig( int nAdapter, int nVendorID, int nDeviceID, KeyValues *pConfiguration )
  560. {
  561. if ( IsX360() )
  562. {
  563. // this is not compatible with xbox
  564. return false;
  565. }
  566. LOCK_SHADERAPI();
  567. VidMatConfigData_t configData;
  568. #ifdef POSIX
  569. V_strcpy_safe( configData.szFileName, "cfg/moddefaults_mac.txt" );
  570. #else
  571. V_strcpy_safe( configData.szFileName, "cfg\\moddefaults.txt" );
  572. #endif
  573. V_strcpy_safe( configData.szPathID, "MOD" );
  574. configData.pConfigKeys = pConfiguration;
  575. configData.nVendorID = nVendorID;
  576. configData.nDeviceID = nDeviceID;
  577. configData.nSystemMemory = GetRam();
  578. int nTextureMemorySize = GetVidMemBytes( nAdapter );
  579. configData.nVideoMemory = nTextureMemorySize / ( 1024 * 1024 );
  580. configData.bIsVideo = true;
  581. configData.nDXLevel = g_pHardwareConfig->GetMaxDXSupportLevel();
  582. GetDesktopResolution( &configData.nPhysicalScreenWidth, &configData.nPhysicalScreenHeight, nAdapter );
  583. int nModeCount = GetModeCount( nAdapter );
  584. configData.displayModes.SetCount( nModeCount );
  585. for ( int i = 0; i < nModeCount; ++i )
  586. {
  587. GetModeInfo( &configData.displayModes[i], nAdapter, i );
  588. }
  589. #if !defined( _X360 )
  590. // Call into the video.cfg file to setup the video config cvars.
  591. RecommendedConfig( configData );
  592. // Update the convars.
  593. UpdateVideoConfigConVars( configData.pConfigKeys );
  594. #endif
  595. return true;
  596. //#endif
  597. }
  598. //-----------------------------------------------------------------------------
  599. // Purpose: Gets the recommended video configuration.
  600. // Called from:
  601. // 3. Used by materialsystem.dll->cmaterialsystem.cpp->GenerateConfigFromConfigKeyValues to fill in material system data (MaterialSystem_Config_t)
  602. // 4. Used by materialsystem.dll->cmaterialsystem.cpp->WriteConfigurationInfoToConVars to write the material system data into ConVars
  603. //-----------------------------------------------------------------------------
  604. bool CShaderDeviceMgrBase::GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, int nVendorID, int nDeviceID, KeyValues *pConfiguration )
  605. {
  606. if ( IsX360() )
  607. {
  608. // this is not compatible with xbox
  609. return false;
  610. }
  611. LOCK_SHADERAPI();
  612. VidMatConfigData_t configData;
  613. #ifdef OSX
  614. V_strcpy_safe( configData.szFileName, "../bin/dxsupport_mac.cfg" );
  615. #elif LINUX
  616. V_strcpy_safe( configData.szFileName, "../bin/dxsupport.cfg" );
  617. #else
  618. V_strcpy_safe( configData.szFileName, "..\\bin\\dxsupport.cfg" );
  619. #endif
  620. V_strcpy_safe( configData.szPathID, "GAME" );
  621. configData.pConfigKeys = pConfiguration;
  622. configData.nVendorID = nVendorID;
  623. configData.nDeviceID = nDeviceID;
  624. configData.nSystemMemory = GetRam();
  625. int nTextureMemorySize = GetVidMemBytes( nAdapter );
  626. configData.nVideoMemory = nTextureMemorySize / ( 1024 * 1024 );
  627. configData.bIsVideo = false;
  628. configData.nDXLevel = g_pHardwareConfig->GetMaxDXSupportLevel();
  629. GetDesktopResolution( &configData.nPhysicalScreenWidth, &configData.nPhysicalScreenHeight, nAdapter );
  630. int nModeCount = GetModeCount( nAdapter );
  631. configData.displayModes.SetCount( nModeCount );
  632. for ( int i = 0; i < nModeCount; ++i )
  633. {
  634. GetModeInfo( &configData.displayModes[i], nAdapter, i );
  635. }
  636. #if !defined( _X360 ) && !defined( _PS3 )
  637. // Call into the video.cfg file to setup the video config cvars.
  638. RecommendedConfig( configData );
  639. #endif
  640. return true;
  641. }
  642. //-----------------------------------------------------------------------------
  643. // Gets recommended congifuration for a particular adapter at a particular dx level
  644. //-----------------------------------------------------------------------------
  645. bool CShaderDeviceMgrBase::GetRecommendedVideoConfig( int nAdapter, KeyValues *pCongifuration )
  646. {
  647. Assert( nAdapter >= 0 && nAdapter <= GetAdapterCount() );
  648. MaterialAdapterInfo_t info;
  649. GetAdapterInfo( nAdapter, info );
  650. return GetRecommendedVideoConfig( nAdapter, info.m_VendorID, info.m_DeviceID, pCongifuration );
  651. }
  652. //-----------------------------------------------------------------------------
  653. // Gets recommended congifuration for a particular adapter at a particular dx level
  654. //-----------------------------------------------------------------------------
  655. bool CShaderDeviceMgrBase::GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, KeyValues *pCongifuration )
  656. {
  657. Assert( nAdapter >= 0 && nAdapter <= GetAdapterCount() );
  658. MaterialAdapterInfo_t info;
  659. GetAdapterInfo( nAdapter, info );
  660. return GetRecommendedConfigurationInfo( nAdapter, nDXLevel, info.m_VendorID, info.m_DeviceID, pCongifuration );
  661. }
  662. //-----------------------------------------------------------------------------
  663. // Returns only valid dx levels
  664. //-----------------------------------------------------------------------------
  665. int CShaderDeviceMgrBase::GetClosestActualDXLevel( int nDxLevel ) const
  666. {
  667. if ( IsX360() )
  668. return 98;
  669. if ( nDxLevel < 92 )
  670. return 90;
  671. if ( nDxLevel < 95 )
  672. return 92;
  673. if ( nDxLevel < 100 )
  674. return 95;
  675. return 100;
  676. }
  677. //-----------------------------------------------------------------------------
  678. // Mode change callback
  679. //-----------------------------------------------------------------------------
  680. void CShaderDeviceMgrBase::AddModeChangeCallback( ShaderModeChangeCallbackFunc_t func )
  681. {
  682. LOCK_SHADERAPI();
  683. Assert( func && m_ModeChangeCallbacks.Find( func ) < 0 );
  684. m_ModeChangeCallbacks.AddToTail( func );
  685. }
  686. void CShaderDeviceMgrBase::RemoveModeChangeCallback( ShaderModeChangeCallbackFunc_t func )
  687. {
  688. LOCK_SHADERAPI();
  689. m_ModeChangeCallbacks.FindAndRemove( func );
  690. }
  691. void CShaderDeviceMgrBase::InvokeModeChangeCallbacks( int screenWidth, int screenHeight )
  692. {
  693. int nCount = m_ModeChangeCallbacks.Count();
  694. for ( int i = 0; i < nCount; ++i )
  695. {
  696. m_ModeChangeCallbacks[i]();
  697. }
  698. nCount = m_DeviceDependentObjects.Count();
  699. for ( int i = 0; i < nCount; ++i )
  700. {
  701. m_DeviceDependentObjects[i]->ScreenSizeChanged( screenWidth, screenHeight );
  702. }
  703. }
  704. void CShaderDeviceMgrBase::AddDeviceDependentObject( IShaderDeviceDependentObject *pObject )
  705. {
  706. if ( pObject )
  707. {
  708. LOCK_SHADERAPI();
  709. Assert( pObject && m_DeviceDependentObjects.Find( pObject ) < 0 );
  710. m_DeviceDependentObjects.AddToTail( pObject );
  711. }
  712. }
  713. void CShaderDeviceMgrBase::RemoveDeviceDependentObject( IShaderDeviceDependentObject *pObject )
  714. {
  715. if ( pObject )
  716. {
  717. LOCK_SHADERAPI();
  718. m_DeviceDependentObjects.FindAndRemove( pObject );
  719. }
  720. }
  721. void CShaderDeviceMgrBase::InvokeDeviceLostNotifications( void )
  722. {
  723. int nCount = m_DeviceDependentObjects.Count();
  724. for ( int i = 0; i < nCount; ++i )
  725. {
  726. m_DeviceDependentObjects[i]->DeviceLost();
  727. }
  728. }
  729. void CShaderDeviceMgrBase::InvokeDeviceResetNotifications( IDirect3DDevice9 *pDevice, D3DPRESENT_PARAMETERS *pPresentParameters, void *pHWnd )
  730. {
  731. int nCount = m_DeviceDependentObjects.Count();
  732. for ( int i = 0; i < nCount; ++i )
  733. {
  734. m_DeviceDependentObjects[i]->DeviceReset( ( void * )pDevice, ( void * )pPresentParameters, pHWnd );
  735. }
  736. }
  737. //-----------------------------------------------------------------------------
  738. // Factory to return from SetMode
  739. //-----------------------------------------------------------------------------
  740. void* CShaderDeviceMgrBase::ShaderInterfaceFactory( const char *pInterfaceName, int *pReturnCode )
  741. {
  742. if ( pReturnCode )
  743. {
  744. *pReturnCode = IFACE_OK;
  745. }
  746. if ( !Q_stricmp( pInterfaceName, SHADER_DEVICE_INTERFACE_VERSION ) )
  747. return static_cast< IShaderDevice* >( g_pShaderDevice );
  748. if ( !Q_stricmp( pInterfaceName, SHADERAPI_INTERFACE_VERSION ) )
  749. return static_cast< IShaderAPI* >( g_pShaderAPI );
  750. if ( !Q_stricmp( pInterfaceName, SHADERSHADOW_INTERFACE_VERSION ) )
  751. return static_cast< IShaderShadow* >( g_pShaderShadow );
  752. if ( pReturnCode )
  753. {
  754. *pReturnCode = IFACE_FAILED;
  755. }
  756. return NULL;
  757. }
  758. //-----------------------------------------------------------------------------
  759. //
  760. // The Base implementation of the shader device
  761. //
  762. //-----------------------------------------------------------------------------
  763. //-----------------------------------------------------------------------------
  764. // constructor, destructor
  765. //-----------------------------------------------------------------------------
  766. CShaderDeviceBase::CShaderDeviceBase()
  767. {
  768. m_bInitialized = false;
  769. m_nAdapter = -1;
  770. m_hWnd = NULL;
  771. m_hWndCookie = NULL;
  772. m_dwThreadId = ThreadGetCurrentId();
  773. }
  774. CShaderDeviceBase::~CShaderDeviceBase()
  775. {
  776. }
  777. void CShaderDeviceBase::SetCurrentThreadAsOwner()
  778. {
  779. m_dwThreadId = ThreadGetCurrentId();
  780. }
  781. void CShaderDeviceBase::RemoveThreadOwner()
  782. {
  783. m_dwThreadId = 0xFFFFFFFF;
  784. }
  785. bool CShaderDeviceBase::ThreadOwnsDevice()
  786. {
  787. if ( ThreadGetCurrentId() == m_dwThreadId )
  788. return true;
  789. return false;
  790. }
  791. // Methods of IShaderDevice
  792. ImageFormat CShaderDeviceBase::GetBackBufferFormat() const
  793. {
  794. return IMAGE_FORMAT_UNKNOWN;
  795. }
  796. int CShaderDeviceBase::StencilBufferBits() const
  797. {
  798. return 0;
  799. }
  800. bool CShaderDeviceBase::IsAAEnabled() const
  801. {
  802. return false;
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Methods for interprocess communication to release resources
  806. //-----------------------------------------------------------------------------
  807. #define MATERIAL_SYSTEM_WINDOW_ID 0xFEEDDEAD
  808. #ifdef USE_ACTUAL_DX
  809. static VD3DHWND GetTopmostParentWindow( VD3DHWND hWnd )
  810. {
  811. // Find the parent window...
  812. VD3DHWND hParent = GetParent( hWnd );
  813. while ( hParent )
  814. {
  815. hWnd = hParent;
  816. hParent = GetParent( hWnd );
  817. }
  818. return hWnd;
  819. }
  820. static BOOL CALLBACK EnumChildWindowsProc( VD3DHWND hWnd, LPARAM lParam )
  821. {
  822. int windowId = GetWindowLongPtr( hWnd, GWLP_USERDATA );
  823. if (windowId == MATERIAL_SYSTEM_WINDOW_ID)
  824. {
  825. COPYDATASTRUCT copyData;
  826. copyData.dwData = lParam;
  827. copyData.cbData = 0;
  828. copyData.lpData = 0;
  829. SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&copyData);
  830. }
  831. return TRUE;
  832. }
  833. static BOOL CALLBACK EnumWindowsProc( VD3DHWND hWnd, LPARAM lParam )
  834. {
  835. EnumChildWindows( hWnd, EnumChildWindowsProc, lParam );
  836. return TRUE;
  837. }
  838. static BOOL CALLBACK EnumWindowsProcNotThis( VD3DHWND hWnd, LPARAM lParam )
  839. {
  840. if ( g_pShaderDevice && ( GetTopmostParentWindow( (VD3DHWND)g_pShaderDevice->GetIPCHWnd() ) == hWnd ) )
  841. return TRUE;
  842. EnumChildWindows( hWnd, EnumChildWindowsProc, lParam );
  843. return TRUE;
  844. }
  845. #endif
  846. //-----------------------------------------------------------------------------
  847. // Adds a hook to let us know when other instances are setting the mode
  848. //-----------------------------------------------------------------------------
  849. #ifdef STRICT
  850. #define WINDOW_PROC WNDPROC
  851. #else
  852. #define WINDOW_PROC FARPROC
  853. #endif
  854. #ifdef USE_ACTUAL_DX
  855. static LRESULT CALLBACK ShaderDX8WndProc(VD3DHWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  856. {
  857. #if !defined( _X360 )
  858. // FIXME: Should these IPC messages tell when an app has focus or not?
  859. // If so, we'd want to totally disable the shader api layer when an app
  860. // doesn't have focus.
  861. // Look for the special IPC message that tells us we're trying to set
  862. // the mode....
  863. switch(msg)
  864. {
  865. case WM_COPYDATA:
  866. {
  867. if ( !g_pShaderDevice )
  868. break;
  869. COPYDATASTRUCT* pData = (COPYDATASTRUCT*)lParam;
  870. // that number is our magic cookie number
  871. if ( pData->dwData == CShaderDeviceBase::RELEASE_MESSAGE )
  872. {
  873. g_pShaderDevice->OtherAppInitializing(true);
  874. }
  875. else if ( pData->dwData == CShaderDeviceBase::REACQUIRE_MESSAGE )
  876. {
  877. g_pShaderDevice->OtherAppInitializing(false);
  878. }
  879. else if ( pData->dwData == CShaderDeviceBase::EVICT_MESSAGE )
  880. {
  881. g_pShaderDevice->EvictManagedResourcesInternal( );
  882. }
  883. }
  884. break;
  885. }
  886. return DefWindowProc( hWnd, msg, wParam, lParam );
  887. #endif
  888. }
  889. #endif
  890. //-----------------------------------------------------------------------------
  891. // Install, remove ability to talk to other shaderapi apps
  892. //-----------------------------------------------------------------------------
  893. void CShaderDeviceBase::InstallWindowHook( void* hWnd )
  894. {
  895. Assert( m_hWndCookie == NULL );
  896. #ifdef USE_ACTUAL_DX
  897. #if !defined( _X360 )
  898. VD3DHWND hParent = GetTopmostParentWindow( (VD3DHWND)hWnd );
  899. // Attach a child window to the parent; we're gonna store special info there
  900. // We can't use the USERDATA, cause other apps may want to use this.
  901. HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr( hParent, GWLP_HINSTANCE );
  902. WNDCLASS wc;
  903. memset( &wc, 0, sizeof( wc ) );
  904. wc.style = CS_NOCLOSE | CS_PARENTDC;
  905. wc.lpfnWndProc = ShaderDX8WndProc;
  906. wc.hInstance = hInst;
  907. wc.lpszClassName = "shaderdx8";
  908. // In case an old one is sitting around still...
  909. UnregisterClass( "shaderdx8", hInst );
  910. RegisterClass( &wc );
  911. // Create the window
  912. m_hWndCookie = CreateWindow( "shaderdx8", "shaderdx8", WS_CHILD,
  913. 0, 0, 0, 0, hParent, NULL, hInst, NULL );
  914. // Marks it as a material system window
  915. SetWindowLongPtr( (VD3DHWND)m_hWndCookie, GWLP_USERDATA, MATERIAL_SYSTEM_WINDOW_ID );
  916. #endif
  917. #endif
  918. }
  919. void CShaderDeviceBase::RemoveWindowHook( void* hWnd )
  920. {
  921. #ifdef USE_ACTUAL_DX
  922. #if !defined( _X360 )
  923. if ( m_hWndCookie )
  924. {
  925. DestroyWindow( (VD3DHWND)m_hWndCookie );
  926. m_hWndCookie = 0;
  927. }
  928. VD3DHWND hParent = GetTopmostParentWindow( (VD3DHWND)hWnd );
  929. HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr( hParent, GWLP_HINSTANCE );
  930. UnregisterClass( "shaderdx8", hInst );
  931. #endif
  932. #endif
  933. }
  934. //-----------------------------------------------------------------------------
  935. // Sends a message to other shaderapi applications
  936. //-----------------------------------------------------------------------------
  937. void CShaderDeviceBase::SendIPCMessage( IPCMessage_t msg )
  938. {
  939. #ifdef USE_ACTUAL_DX
  940. #if !defined( _X360 )
  941. // Gotta send this to all windows, since we don't know which ones
  942. // are material system apps...
  943. if ( msg != EVICT_MESSAGE )
  944. {
  945. EnumWindows( EnumWindowsProc, (DWORD)msg );
  946. }
  947. else
  948. {
  949. EnumWindows( EnumWindowsProcNotThis, (DWORD)msg );
  950. }
  951. #endif
  952. #endif
  953. }
  954. //-----------------------------------------------------------------------------
  955. // Find view
  956. //-----------------------------------------------------------------------------
  957. int CShaderDeviceBase::FindView( void* hWnd ) const
  958. {
  959. /* FIXME: Is this necessary?
  960. // Look for the view in the list of views
  961. for (int i = m_Views.Count(); --i >= 0; )
  962. {
  963. if (m_Views[i].m_HWnd == (VD3DHWND)hwnd)
  964. return i;
  965. }
  966. */
  967. return -1;
  968. }
  969. //-----------------------------------------------------------------------------
  970. // Creates a child window
  971. //-----------------------------------------------------------------------------
  972. bool CShaderDeviceBase::AddView( void* hWnd )
  973. {
  974. LOCK_SHADERAPI();
  975. /*
  976. // If we haven't created a device yet
  977. if (!Dx9Device())
  978. return false;
  979. // Make sure no duplicate hwnds...
  980. if (FindView(hwnd) >= 0)
  981. return false;
  982. // In this case, we need to create the device; this is our
  983. // default swap chain. This here says we're gonna use a part of the
  984. // existing buffer and just grab that.
  985. int view = m_Views.AddToTail();
  986. m_Views[view].m_HWnd = (VD3DHWND)hwnd;
  987. // memcpy( &m_Views[view].m_PresentParamters, m_PresentParameters, sizeof(m_PresentParamters) );
  988. HRESULT hr;
  989. hr = Dx9Device()->CreateAdditionalSwapChain( &m_PresentParameters,
  990. &m_Views[view].m_pSwapChain );
  991. return !FAILED(hr);
  992. */
  993. return true;
  994. }
  995. void CShaderDeviceBase::RemoveView( void* hWnd )
  996. {
  997. LOCK_SHADERAPI();
  998. /*
  999. // Look for the view in the list of views
  1000. int i = FindView(hwnd);
  1001. if (i >= 0)
  1002. {
  1003. // FIXME m_Views[i].m_pSwapChain->Release();
  1004. m_Views.FastRemove(i);
  1005. }
  1006. */
  1007. }
  1008. //-----------------------------------------------------------------------------
  1009. // Activates a child window
  1010. //-----------------------------------------------------------------------------
  1011. void CShaderDeviceBase::SetView( void* hWnd )
  1012. {
  1013. LOCK_SHADERAPI();
  1014. ShaderViewport_t viewport;
  1015. g_pShaderAPI->GetViewports( &viewport, 1 );
  1016. // Get the window (*not* client) rect of the view window
  1017. m_ViewHWnd = (VD3DHWND)hWnd;
  1018. GetWindowSize( m_nWindowWidth, m_nWindowHeight );
  1019. // Reset the viewport (takes into account the view rect)
  1020. // Don't need to set the viewport if it's not ready
  1021. g_pShaderAPI->SetViewports( 1, &viewport );
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. // Gets the window size
  1025. //-----------------------------------------------------------------------------
  1026. void CShaderDeviceBase::GetWindowSize( int& nWidth, int& nHeight ) const
  1027. {
  1028. #if defined( USE_SDL )
  1029. // this matches up to what the threaded material system does
  1030. g_pShaderAPI->GetBackBufferDimensions( nWidth, nHeight );
  1031. #else
  1032. // If the window was minimized last time swap buffers happened, or if it's iconic now,
  1033. // return 0 size
  1034. #ifdef _WIN32
  1035. if ( !m_bIsMinimized && !IsIconic( ( HWND )m_hWnd ) )
  1036. #else
  1037. if ( !m_bIsMinimized && !IsIconic( (VD3DHWND)m_hWnd ) )
  1038. #endif
  1039. {
  1040. // NOTE: Use the 'current view' (which may be the same as the main window)
  1041. RECT rect;
  1042. #ifdef _WIN32
  1043. GetClientRect( ( HWND )m_ViewHWnd, &rect );
  1044. #else
  1045. toglGetClientRect( (VD3DHWND)m_ViewHWnd, &rect );
  1046. #endif
  1047. nWidth = rect.right - rect.left;
  1048. nHeight = rect.bottom - rect.top;
  1049. }
  1050. else
  1051. {
  1052. nWidth = nHeight = 0;
  1053. }
  1054. #endif
  1055. }