Team Fortress 2 Source Code as on 22/4/2020
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

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