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.

3707 lines
122 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #define DISABLE_PROTECTED_THINGS
  9. #include "locald3dtypes.h"
  10. #include "shaderdevicedx8.h"
  11. #include "shaderapi/ishaderutil.h"
  12. #include "shaderapidx8_global.h"
  13. #include "filesystem.h"
  14. #include "tier0/icommandline.h"
  15. #include "tier2/tier2.h"
  16. #include "shadershadowdx8.h"
  17. #include "colorformatdx8.h"
  18. #include "materialsystem/IShader.h"
  19. #include "shaderapidx8.h"
  20. #include "shaderapidx8_global.h"
  21. #include "imeshdx8.h"
  22. #include "materialsystem/materialsystem_config.h"
  23. #include "vertexshaderdx8.h"
  24. #include "recording.h"
  25. #include "winutils.h"
  26. #include "tier0/vprof_telemetry.h"
  27. #if defined ( DX_TO_GL_ABSTRACTION )
  28. // Placed here so inlines placed in dxabstract.h can access gGL
  29. COpenGLEntryPoints *gGL = NULL;
  30. #endif
  31. #define D3D_BATCH_PERF_ANALYSIS 0
  32. #if D3D_BATCH_PERF_ANALYSIS
  33. #if defined( DX_TO_GL_ABSTRACTION )
  34. #error Cannot enable D3D_BATCH_PERF_ANALYSIS when using DX_TO_GL_ABSTRACTION, use GL_BATCH_PERF_ANALYSIS instead.
  35. #endif
  36. // Define this if you want all d3d9 interfaces hooked and run through the dx9hook.h shim interfaces. For profiling, etc.
  37. #define DO_DX9_HOOK
  38. #endif
  39. #ifdef DO_DX9_HOOK
  40. #if D3D_BATCH_PERF_ANALYSIS
  41. ConVar d3d_batch_vis( "d3d_batch_vis", "0" );
  42. ConVar d3d_batch_vis_abs_scale( "d3d_batch_vis_abs_scale", ".050" );
  43. ConVar d3d_present_vis_abs_scale( "d3d_batch_vis_abs_scale", ".050" );
  44. ConVar d3d_batch_vis_y_scale( "d3d_batch_vis_y_scale", "0.0" );
  45. uint64 g_nTotalD3DCalls, g_nTotalD3DCycles;
  46. static double s_rdtsc_to_ms;
  47. #endif
  48. #include "dx9hook.h"
  49. #endif
  50. #ifndef _X360
  51. #include "wmi.h"
  52. #endif
  53. #if defined( _X360 )
  54. #include "xbox/xbox_console.h"
  55. #include "xbox/xbox_win32stubs.h"
  56. #endif
  57. //#define DX8_COMPATABILITY_MODE
  58. //-----------------------------------------------------------------------------
  59. // Globals
  60. //-----------------------------------------------------------------------------
  61. static CShaderDeviceMgrDx8 g_ShaderDeviceMgrDx8;
  62. CShaderDeviceMgrDx8* g_pShaderDeviceMgrDx8 = &g_ShaderDeviceMgrDx8;
  63. #ifndef SHADERAPIDX10
  64. // In the shaderapidx10.dll, we use its version of IShaderDeviceMgr.
  65. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderDeviceMgrDx8, IShaderDeviceMgr,
  66. SHADER_DEVICE_MGR_INTERFACE_VERSION, g_ShaderDeviceMgrDx8 )
  67. #endif
  68. #if defined( _X360 )
  69. IDirect3D9 *m_pD3D;
  70. #endif
  71. IDirect3DDevice *g_pD3DDevice = NULL;
  72. #if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
  73. // HACK: need to pass knowledge of D3D9Ex usage into callers of D3D Create* methods
  74. // so they do not try to specify D3DPOOL_MANAGED, which is unsupported in D3D9Ex
  75. bool g_ShaderDeviceUsingD3D9Ex = false;
  76. static ConVar mat_supports_d3d9ex( "mat_supports_d3d9ex", "0", FCVAR_HIDDEN );
  77. #endif
  78. // hook into mat_forcedynamic from the engine.
  79. static ConVar mat_forcedynamic( "mat_forcedynamic", "0", FCVAR_CHEAT );
  80. // this is hooked into the engines convar
  81. ConVar mat_debugalttab( "mat_debugalttab", "0", FCVAR_CHEAT );
  82. //-----------------------------------------------------------------------------
  83. //
  84. // Device manager
  85. //
  86. //-----------------------------------------------------------------------------
  87. //-----------------------------------------------------------------------------
  88. // constructor, destructor
  89. //-----------------------------------------------------------------------------
  90. CShaderDeviceMgrDx8::CShaderDeviceMgrDx8()
  91. {
  92. m_pD3D = NULL;
  93. m_bObeyDxCommandlineOverride = true;
  94. m_bAdapterInfoIntialized = false;
  95. #if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
  96. m_hD3D9 = NULL;
  97. m_pBeginEvent = NULL;
  98. m_pEndEvent = NULL;
  99. m_pSetMarker = NULL;
  100. m_pSetOptions = NULL;
  101. #endif
  102. }
  103. CShaderDeviceMgrDx8::~CShaderDeviceMgrDx8()
  104. {
  105. }
  106. #ifdef OSX
  107. #include <Carbon/Carbon.h>
  108. #endif
  109. //-----------------------------------------------------------------------------
  110. // Connect, disconnect
  111. //-----------------------------------------------------------------------------
  112. bool CShaderDeviceMgrDx8::Connect( CreateInterfaceFn factory )
  113. {
  114. LOCK_SHADERAPI();
  115. if ( !BaseClass::Connect( factory ) )
  116. return false;
  117. #if defined ( DX_TO_GL_ABSTRACTION )
  118. gGL = ToGLConnectLibraries( factory );
  119. #endif
  120. #if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9) && !defined(RECORDING) && !defined( DX_TO_GL_ABSTRACTION )
  121. m_pD3D = NULL;
  122. // Attempt to create a D3D9Ex device (Windows Vista and later) if possible
  123. bool bD3D9ExForceDisable = ( CommandLine()->FindParm( "-nod3d9ex" ) != 0 ) ||
  124. ( CommandLine()->ParmValue( "-dxlevel", 95 ) < 90 );
  125. bool bD3D9ExAvailable = false;
  126. if ( HMODULE hMod = ::LoadLibraryA( "d3d9.dll" ) )
  127. {
  128. typedef HRESULT ( WINAPI *CreateD3D9ExFunc_t )( UINT, IUnknown** );
  129. if ( CreateD3D9ExFunc_t pfnCreateD3D9Ex = (CreateD3D9ExFunc_t) ::GetProcAddress( hMod, "Direct3DCreate9Ex" ) )
  130. {
  131. IUnknown *pD3D9Ex = NULL;
  132. if ( (*pfnCreateD3D9Ex)( D3D_SDK_VERSION, &pD3D9Ex ) == S_OK && pD3D9Ex )
  133. {
  134. bD3D9ExAvailable = true;
  135. if ( bD3D9ExForceDisable )
  136. {
  137. pD3D9Ex->Release();
  138. }
  139. else
  140. {
  141. g_ShaderDeviceUsingD3D9Ex = true;
  142. // The following is more "correct" but incompatible with the Steam overlay:
  143. //pD3D9Ex->QueryInterface( IID_IDirect3D9, (void**) &m_pD3D );
  144. //pD3D9Ex->Release();
  145. m_pD3D = static_cast< IDirect3D9* >( pD3D9Ex );
  146. }
  147. }
  148. }
  149. ::FreeLibrary( hMod );
  150. }
  151. if ( !m_pD3D )
  152. {
  153. g_ShaderDeviceUsingD3D9Ex = false;
  154. m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
  155. }
  156. mat_supports_d3d9ex.SetValue( bD3D9ExAvailable ? 1 : 0 );
  157. #else
  158. #if defined( DO_DX9_HOOK )
  159. m_pD3D = Direct3DCreate9Hook(D3D_SDK_VERSION);
  160. #else
  161. m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
  162. #endif
  163. #endif
  164. if ( !m_pD3D )
  165. {
  166. Warning( "Failed to create D3D9!\n" );
  167. return false;
  168. }
  169. #if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
  170. // This is a little odd, but AMD PerfStudio hooks D3D9.DLL and intercepts all of the D3DPERF API's (even for OpenGL apps).
  171. // So dynamically load d3d9.dll and get the address of these exported functions.
  172. if ( !m_hD3D9 )
  173. {
  174. m_hD3D9 = LoadLibraryA("d3d9.dll");
  175. }
  176. if ( m_hD3D9 )
  177. {
  178. Plat_DebugString( "PIX_INSTRUMENTATION: Loaded d3d9.dll\n" );
  179. printf( "PIX_INSTRUMENTATION: Loaded d3d9.dll\n" );
  180. m_pBeginEvent = (D3DPERF_BeginEvent_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_BeginEvent" );
  181. m_pEndEvent = (D3DPERF_EndEvent_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_EndEvent" );
  182. m_pSetMarker = (D3DPERF_SetMarker_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_SetOptions" );
  183. m_pSetOptions = (D3DPERF_SetOptions_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_SetMarker" );
  184. }
  185. #endif
  186. // FIXME: Want this to be here, but we can't because Steam
  187. // hasn't had it's application ID set up yet.
  188. // InitAdapterInfo();
  189. return true;
  190. }
  191. void CShaderDeviceMgrDx8::Disconnect()
  192. {
  193. LOCK_SHADERAPI();
  194. #if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
  195. if ( m_hD3D9 )
  196. {
  197. m_pBeginEvent = NULL;
  198. m_pEndEvent = NULL;
  199. m_pSetMarker = NULL;
  200. m_pSetOptions = NULL;
  201. FreeLibrary( m_hD3D9 );
  202. m_hD3D9 = NULL;
  203. }
  204. #endif
  205. if ( m_pD3D )
  206. {
  207. m_pD3D->Release();
  208. m_pD3D = 0;
  209. }
  210. #if defined ( DX_TO_GL_ABSTRACTION )
  211. ToGLDisconnectLibraries();
  212. #endif
  213. BaseClass::Disconnect();
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Initialization
  217. //-----------------------------------------------------------------------------
  218. InitReturnVal_t CShaderDeviceMgrDx8::Init( )
  219. {
  220. // FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
  221. // Do it in Connect instead.
  222. InitAdapterInfo();
  223. return INIT_OK;
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Shutdown
  227. //-----------------------------------------------------------------------------
  228. void CShaderDeviceMgrDx8::Shutdown( )
  229. {
  230. LOCK_SHADERAPI();
  231. // FIXME: Make PIX work
  232. // BeginPIXEvent( PIX_VALVE_ORANGE, "Shutdown" );
  233. if ( g_pShaderAPI )
  234. {
  235. g_pShaderAPI->OnDeviceShutdown();
  236. }
  237. if ( g_pShaderDevice )
  238. {
  239. g_pShaderDevice->ShutdownDevice();
  240. g_pMaterialSystemHardwareConfig = NULL;
  241. }
  242. // EndPIXEvent();
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Inline methods
  246. //-----------------------------------------------------------------------------
  247. //-----------------------------------------------------------------------------
  248. // Initialize adapter information
  249. //-----------------------------------------------------------------------------
  250. void CShaderDeviceMgrDx8::InitAdapterInfo()
  251. {
  252. if ( m_bAdapterInfoIntialized )
  253. return;
  254. m_bAdapterInfoIntialized = true;
  255. m_Adapters.RemoveAll();
  256. Assert(m_pD3D);
  257. int nCount = m_pD3D->GetAdapterCount( );
  258. for( int i = 0; i < nCount; ++i )
  259. {
  260. int j = m_Adapters.AddToTail();
  261. AdapterInfo_t &info = m_Adapters[j];
  262. #ifdef _DEBUG
  263. memset( &info.m_ActualCaps, 0xDD, sizeof(info.m_ActualCaps) );
  264. #endif
  265. info.m_ActualCaps.m_bDeviceOk = ComputeCapsFromD3D( &info.m_ActualCaps, i );
  266. if ( !info.m_ActualCaps.m_bDeviceOk )
  267. continue;
  268. ReadDXSupportLevels( info.m_ActualCaps );
  269. // Read dxsupport.cfg which has config overrides for particular cards.
  270. ReadHardwareCaps( info.m_ActualCaps, info.m_ActualCaps.m_nMaxDXSupportLevel );
  271. // What's in "-shader" overrides dxsupport.cfg
  272. const char *pShaderParam = CommandLine()->ParmValue( "-shader" );
  273. if ( pShaderParam )
  274. {
  275. Q_strncpy( info.m_ActualCaps.m_pShaderDLL, pShaderParam, sizeof( info.m_ActualCaps.m_pShaderDLL ) );
  276. }
  277. }
  278. }
  279. //--------------------------------------------------------------------------------
  280. // Code to detect support for texture border color (widely supported but the caps
  281. // bit is messed up in drivers due to a stupid WHQL test that requires this to work
  282. // with float textures which we don't generally care about wrt this address mode)
  283. //--------------------------------------------------------------------------------
  284. void CShaderDeviceMgrDx8::CheckBorderColorSupport( HardwareCaps_t *pCaps, int nAdapter )
  285. {
  286. #ifdef DX_TO_GL_ABSTRACTION
  287. if( true )
  288. #else
  289. if( IsX360() )
  290. #endif
  291. {
  292. pCaps->m_bSupportsBorderColor = true;
  293. }
  294. else // Most PC parts do this, but let's not deal with that yet (JasonM)
  295. {
  296. pCaps->m_bSupportsBorderColor = false;
  297. }
  298. }
  299. //--------------------------------------------------------------------------------
  300. // Vendor-dependent code to detect support for various flavors of shadow mapping
  301. //--------------------------------------------------------------------------------
  302. void CShaderDeviceMgrDx8::CheckVendorDependentShadowMappingSupport( HardwareCaps_t *pCaps, int nAdapter )
  303. {
  304. // Set a default null texture format...may be overridden below by IHV-specific surface type
  305. pCaps->m_NullTextureFormat = IMAGE_FORMAT_ARGB8888;
  306. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_R5G6B5 ) == S_OK )
  307. {
  308. pCaps->m_NullTextureFormat = IMAGE_FORMAT_RGB565;
  309. }
  310. #if defined( _X360 )
  311. pCaps->m_ShadowDepthTextureFormat = ReverseDepthOnX360() ? IMAGE_FORMAT_X360_DST24F : IMAGE_FORMAT_X360_DST24;
  312. pCaps->m_bSupportsShadowDepthTextures = true;
  313. pCaps->m_bSupportsFetch4 = false;
  314. return;
  315. #elif defined ( DX_TO_GL_ABSTRACTION )
  316. // We may want to only do this on the higher-end Mac SKUs, since it's not free...
  317. pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST16; // This format shunts us down the right shader combo path
  318. pCaps->m_bSupportsShadowDepthTextures = true;
  319. pCaps->m_bSupportsFetch4 = false;
  320. return;
  321. #endif
  322. if ( IsPC() || !IsX360() )
  323. {
  324. bool bToolsMode = IsWindows() && ( CommandLine()->CheckParm( "-tools" ) != NULL );
  325. bool bFound16Bit = false;
  326. if ( ( pCaps->m_VendorID == VENDORID_NVIDIA ) && ( pCaps->m_SupportsShaderModel_3_0 ) ) // ps_3_0 parts from nVidia
  327. {
  328. // First, test for null texture support
  329. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, NVFMT_NULL ) == S_OK )
  330. {
  331. pCaps->m_NullTextureFormat = IMAGE_FORMAT_NV_NULL;
  332. }
  333. //
  334. // NVIDIA has two no-PCF formats (these are not filtering modes, but surface formats
  335. // NVFMT_RAWZ is supported by NV4x (not supported here yet...requires a dp3 to reconstruct in shader code, which doesn't seem to work)
  336. // NVFMT_INTZ is supported on newer chips as of G8x (just read like ATI non-fetch4 mode)
  337. //
  338. /*
  339. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, NVFMT_INTZ ) == S_OK )
  340. {
  341. pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_INTZ;
  342. pCaps->m_bSupportsFetch4 = false;
  343. pCaps->m_bSupportsShadowDepthTextures = true;
  344. return;
  345. }
  346. */
  347. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_D16 ) == S_OK )
  348. {
  349. pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST16;
  350. pCaps->m_bSupportsFetch4 = false;
  351. pCaps->m_bSupportsShadowDepthTextures = true;
  352. bFound16Bit = true;
  353. if ( !bToolsMode ) // Tools will continue on and try for 24 bit...
  354. return;
  355. }
  356. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_D24S8 ) == S_OK )
  357. {
  358. pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST24;
  359. pCaps->m_bSupportsFetch4 = false;
  360. pCaps->m_bSupportsShadowDepthTextures = true;
  361. return;
  362. }
  363. if ( bFound16Bit ) // Found 16 bit but not 24
  364. return;
  365. }
  366. else if ( ( pCaps->m_VendorID == VENDORID_ATI ) && pCaps->m_SupportsPixelShaders_2_b ) // ps_2_b parts from ATI
  367. {
  368. // Initially, check for Fetch4 (tied to ATIFMT_D24S8 support)
  369. pCaps->m_bSupportsFetch4 = false;
  370. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D24S8 ) == S_OK )
  371. {
  372. pCaps->m_bSupportsFetch4 = true;
  373. }
  374. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D16 ) == S_OK ) // Prefer 16-bit
  375. {
  376. pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_ATI_DST16;
  377. pCaps->m_bSupportsShadowDepthTextures = true;
  378. bFound16Bit = true;
  379. if ( !bToolsMode ) // Tools will continue on and try for 24 bit...
  380. return;
  381. }
  382. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D24S8 ) == S_OK )
  383. {
  384. pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_ATI_DST24;
  385. pCaps->m_bSupportsShadowDepthTextures = true;
  386. return;
  387. }
  388. if ( bFound16Bit ) // Found 16 bit but not 24
  389. return;
  390. }
  391. }
  392. // Other vendor or old hardware
  393. pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_UNKNOWN;
  394. pCaps->m_bSupportsShadowDepthTextures = false;
  395. pCaps->m_bSupportsFetch4 = false;
  396. }
  397. //-----------------------------------------------------------------------------
  398. // Vendor-dependent code to detect Alpha To Coverage Backdoors
  399. //-----------------------------------------------------------------------------
  400. void CShaderDeviceMgrDx8::CheckVendorDependentAlphaToCoverage( HardwareCaps_t *pCaps, int nAdapter )
  401. {
  402. pCaps->m_bSupportsAlphaToCoverage = false;
  403. // Bail out on OpenGL
  404. #ifdef DX_TO_GL_ABSTRACTION
  405. pCaps->m_bSupportsAlphaToCoverage = true;
  406. pCaps->m_AlphaToCoverageEnableValue = TRUE;
  407. pCaps->m_AlphaToCoverageDisableValue = FALSE;
  408. pCaps->m_AlphaToCoverageState = D3DRS_ADAPTIVETESS_Y; // Just match the NVIDIA state hackery
  409. return;
  410. #endif
  411. if ( pCaps->m_nDXSupportLevel < 90 )
  412. return;
  413. #ifdef _X360
  414. {
  415. pCaps->m_bSupportsAlphaToCoverage = true;
  416. pCaps->m_AlphaToCoverageEnableValue = TRUE;
  417. pCaps->m_AlphaToCoverageDisableValue = FALSE;
  418. pCaps->m_AlphaToCoverageState = D3DRS_ALPHATOMASKENABLE;
  419. return;
  420. }
  421. #endif // _X360
  422. if ( pCaps->m_VendorID == VENDORID_NVIDIA )
  423. {
  424. // nVidia has two modes...assume SSAA is superior to MSAA and hence more desirable (though it's probably not)
  425. //
  426. // Currently, they only seem to expose any of this on 7800 and up though older parts certainly
  427. // support at least the MSAA mode since they support it on OpenGL via the arb_multisample extension
  428. bool bNVIDIA_MSAA = false;
  429. bool bNVIDIA_SSAA = false;
  430. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, // Check MSAA version
  431. D3DFMT_X8R8G8B8, 0, D3DRTYPE_SURFACE,
  432. (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')) == S_OK )
  433. {
  434. bNVIDIA_MSAA = true;
  435. }
  436. if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, // Check SSAA version
  437. D3DFMT_X8R8G8B8, 0, D3DRTYPE_SURFACE,
  438. (D3DFORMAT)MAKEFOURCC('S', 'S', 'A', 'A')) == S_OK )
  439. {
  440. bNVIDIA_SSAA = true;
  441. }
  442. // nVidia pitches SSAA but we prefer ATOC
  443. if ( bNVIDIA_MSAA )// || bNVIDIA_SSAA )
  444. {
  445. // if ( bNVIDIA_SSAA )
  446. // m_AlphaToCoverageEnableValue = MAKEFOURCC('S', 'S', 'A', 'A');
  447. // else
  448. pCaps->m_AlphaToCoverageEnableValue = MAKEFOURCC('A', 'T', 'O', 'C');
  449. pCaps->m_AlphaToCoverageState = D3DRS_ADAPTIVETESS_Y;
  450. pCaps->m_AlphaToCoverageDisableValue = (DWORD)D3DFMT_UNKNOWN;
  451. pCaps->m_bSupportsAlphaToCoverage = true;
  452. return;
  453. }
  454. }
  455. else if ( pCaps->m_VendorID == VENDORID_ATI )
  456. {
  457. // Supported on all ATI parts...just go ahead and set the state when appropriate
  458. pCaps->m_AlphaToCoverageState = D3DRS_POINTSIZE;
  459. pCaps->m_AlphaToCoverageEnableValue = MAKEFOURCC('A','2','M','1');
  460. pCaps->m_AlphaToCoverageDisableValue = MAKEFOURCC('A','2','M','0');
  461. pCaps->m_bSupportsAlphaToCoverage = true;
  462. return;
  463. }
  464. }
  465. ConVar mat_hdr_level( "mat_hdr_level", "2", FCVAR_ARCHIVE );
  466. ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT );
  467. #ifdef DX_TO_GL_ABSTRACTION
  468. ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "20", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
  469. #else
  470. ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT );
  471. #endif
  472. // For testing Fast Clip
  473. ConVar mat_fastclip( "mat_fastclip", "0", FCVAR_CHEAT );
  474. //-----------------------------------------------------------------------------
  475. // Determine capabilities
  476. //-----------------------------------------------------------------------------
  477. bool CShaderDeviceMgrDx8::ComputeCapsFromD3D( HardwareCaps_t *pCaps, int nAdapter )
  478. {
  479. D3DCAPS caps;
  480. D3DADAPTER_IDENTIFIER9 ident;
  481. HRESULT hr;
  482. // NOTE: When getting the caps, we want to be limited by the hardware
  483. // even if we're running with software T&L...
  484. hr = m_pD3D->GetDeviceCaps( nAdapter, DX8_DEVTYPE, &caps );
  485. if ( FAILED( hr ) )
  486. return false;
  487. hr = m_pD3D->GetAdapterIdentifier( nAdapter, D3DENUM_WHQL_LEVEL, &ident );
  488. if ( FAILED( hr ) )
  489. return false;
  490. if ( IsOpenGL() )
  491. {
  492. if ( !ident.DeviceId && !ident.VendorId )
  493. {
  494. ident.DeviceId = 1; // fake default device/vendor ID for OpenGL
  495. ident.VendorId = 1;
  496. }
  497. }
  498. // Intended for debugging only
  499. if ( CommandLine()->CheckParm( "-force_device_id" ) )
  500. {
  501. const char *pDevID = CommandLine()->ParmValue( "-force_device_id", "" );
  502. if ( pDevID )
  503. {
  504. int nDevID = V_atoi( pDevID ); // use V_atoi for hex support
  505. if ( nDevID > 0 )
  506. {
  507. ident.DeviceId = nDevID;
  508. }
  509. }
  510. }
  511. // Intended for debugging only
  512. if ( CommandLine()->CheckParm( "-force_vendor_id" ) )
  513. {
  514. const char *pVendorID = CommandLine()->ParmValue( "-force_vendor_id", "" );
  515. if ( pVendorID )
  516. {
  517. int nVendorID = V_atoi( pVendorID ); // use V_atoi for hex support
  518. if ( pVendorID > 0 )
  519. {
  520. ident.VendorId = nVendorID;
  521. }
  522. }
  523. }
  524. Q_strncpy( pCaps->m_pDriverName, ident.Description, MATERIAL_ADAPTER_NAME_LENGTH );
  525. pCaps->m_VendorID = ident.VendorId;
  526. pCaps->m_DeviceID = ident.DeviceId;
  527. pCaps->m_SubSysID = ident.SubSysId;
  528. pCaps->m_Revision = ident.Revision;
  529. pCaps->m_nDriverVersionHigh = ident.DriverVersion.HighPart;
  530. pCaps->m_nDriverVersionLow = ident.DriverVersion.LowPart;
  531. pCaps->m_pShaderDLL[0] = 0;
  532. pCaps->m_nMaxViewports = 1;
  533. pCaps->m_PreferDynamicTextures = ( caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES ) ? 1 : 0;
  534. pCaps->m_HasProjectedBumpEnv = ( caps.TextureCaps & D3DPTEXTURECAPS_NOPROJECTEDBUMPENV ) == 0;
  535. pCaps->m_HasSetDeviceGammaRamp = (caps.Caps2 & D3DCAPS2_CANCALIBRATEGAMMA) != 0;
  536. pCaps->m_SupportsVertexShaders = ((caps.VertexShaderVersion >> 8) & 0xFF) >= 1;
  537. pCaps->m_SupportsPixelShaders = ((caps.PixelShaderVersion >> 8) & 0xFF) >= 1;
  538. pCaps->m_bScissorSupported = ( caps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST ) != 0;
  539. #if defined( DX8_COMPATABILITY_MODE )
  540. pCaps->m_SupportsPixelShaders_1_4 = false;
  541. pCaps->m_SupportsPixelShaders_2_0 = false;
  542. pCaps->m_SupportsPixelShaders_2_b = false;
  543. pCaps->m_SupportsVertexShaders_2_0 = false;
  544. pCaps->m_SupportsShaderModel_3_0 = false;
  545. pCaps->m_SupportsMipmappedCubemaps = false;
  546. #else
  547. pCaps->m_SupportsPixelShaders_1_4 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0104;
  548. pCaps->m_SupportsPixelShaders_2_0 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0200;
  549. pCaps->m_SupportsPixelShaders_2_b = ( ( caps.PixelShaderVersion & 0xffff ) >= 0x0200) && (caps.PS20Caps.NumInstructionSlots >= 512); // More caps to this, but this will do
  550. pCaps->m_SupportsVertexShaders_2_0 = ( caps.VertexShaderVersion & 0xffff ) >= 0x0200;
  551. pCaps->m_SupportsShaderModel_3_0 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0300;
  552. pCaps->m_SupportsMipmappedCubemaps = ( caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP ) ? true : false;
  553. #endif
  554. // Slam this off for OpenGL
  555. if ( IsOpenGL() )
  556. {
  557. pCaps->m_SupportsShaderModel_3_0 = false;
  558. }
  559. // Slam 3.0 shaders off for Intel
  560. if ( pCaps->m_VendorID == VENDORID_INTEL )
  561. {
  562. pCaps->m_SupportsShaderModel_3_0 = false;
  563. }
  564. pCaps->m_MaxVertexShader30InstructionSlots = 0;
  565. pCaps->m_MaxPixelShader30InstructionSlots = 0;
  566. if ( pCaps->m_SupportsShaderModel_3_0 )
  567. {
  568. pCaps->m_MaxVertexShader30InstructionSlots = caps.MaxVertexShader30InstructionSlots;
  569. pCaps->m_MaxPixelShader30InstructionSlots = caps.MaxPixelShader30InstructionSlots;
  570. }
  571. if( CommandLine()->CheckParm( "-nops2b" ) )
  572. {
  573. pCaps->m_SupportsPixelShaders_2_b = false;
  574. }
  575. pCaps->m_bSoftwareVertexProcessing = false;
  576. if ( IsWindows() && CommandLine()->CheckParm( "-mat_softwaretl" ) )
  577. {
  578. pCaps->m_bSoftwareVertexProcessing = true;
  579. }
  580. if ( IsWindows() && !( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) )
  581. {
  582. // no hardware t&l. . use software
  583. pCaps->m_bSoftwareVertexProcessing = true;
  584. }
  585. // Set mat_forcedynamic if software vertex processing since the software vp pipe has
  586. // problems with sparse vertex buffers (it transforms the whole thing.)
  587. if ( pCaps->m_bSoftwareVertexProcessing )
  588. {
  589. mat_forcedynamic.SetValue( 1 );
  590. }
  591. if ( pCaps->m_bSoftwareVertexProcessing )
  592. {
  593. pCaps->m_SupportsVertexShaders = true;
  594. pCaps->m_SupportsVertexShaders_2_0 = true;
  595. }
  596. #ifdef OSX
  597. // Static control flow is disabled by default on OSX (the Mac version of togl has known bugs preventing this path from working properly that we've fixed in togl linux/win)
  598. pCaps->m_bSupportsStaticControlFlow = CommandLine()->CheckParm( "-glslcontrolflow" ) != NULL;
  599. #else
  600. pCaps->m_bSupportsStaticControlFlow = !CommandLine()->CheckParm( "-noglslcontrolflow" );
  601. #endif
  602. // NOTE: Texture stages is a fixed-function concept
  603. // NOTE: Normally, the number of texture units == the number of texture
  604. // stages except for NVidia hardware, which reports more stages than units.
  605. // The reason for this is because they expose the inner hardware pixel
  606. // pipeline through the extra stages. The only thing we use stages for
  607. // in the hardware is for configuring the color + alpha args + ops.
  608. pCaps->m_NumSamplers = caps.MaxSimultaneousTextures;
  609. pCaps->m_NumTextureStages = caps.MaxTextureBlendStages;
  610. if ( pCaps->m_SupportsPixelShaders_2_0 )
  611. {
  612. pCaps->m_NumSamplers = 16;
  613. }
  614. else
  615. {
  616. Assert( pCaps->m_NumSamplers <= pCaps->m_NumTextureStages );
  617. }
  618. // Clamp
  619. pCaps->m_NumSamplers = min( pCaps->m_NumSamplers, (int)MAX_SAMPLERS );
  620. pCaps->m_NumTextureStages = min( pCaps->m_NumTextureStages, (int)MAX_TEXTURE_STAGES );
  621. if ( D3DSupportsCompressedTextures() )
  622. {
  623. pCaps->m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
  624. }
  625. else
  626. {
  627. pCaps->m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
  628. }
  629. pCaps->m_bSupportsAnisotropicFiltering = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) != 0;
  630. pCaps->m_bSupportsMagAnisotropicFiltering = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
  631. // OpenGL does not support this--at least not on OSX which is the primary GL target, so just don't use that path on GL at all.
  632. #if !defined( DX_TO_GL_ABSTRACTION )
  633. pCaps->m_bCanStretchRectFromTextures = ( ( caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES ) != 0 ) && ( pCaps->m_VendorID != VENDORID_INTEL );
  634. #else
  635. pCaps->m_bCanStretchRectFromTextures = false;
  636. #endif
  637. pCaps->m_nMaxAnisotropy = pCaps->m_bSupportsAnisotropicFiltering ? caps.MaxAnisotropy : 1;
  638. pCaps->m_SupportsCubeMaps = ( caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP ) ? true : false;
  639. pCaps->m_SupportsNonPow2Textures =
  640. ( !( caps.TextureCaps & D3DPTEXTURECAPS_POW2 ) ||
  641. ( caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL ) );
  642. Assert( caps.TextureCaps & D3DPTEXTURECAPS_PROJECTED );
  643. if ( pCaps->m_bSoftwareVertexProcessing )
  644. {
  645. // This should be pushed down based on pixel shaders.
  646. pCaps->m_NumVertexShaderConstants = 256;
  647. pCaps->m_NumBooleanVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
  648. pCaps->m_NumBooleanPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
  649. pCaps->m_NumIntegerVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
  650. pCaps->m_NumIntegerPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
  651. }
  652. else
  653. {
  654. pCaps->m_NumVertexShaderConstants = caps.MaxVertexShaderConst;
  655. if ( CommandLine()->FindParm( "-limitvsconst" ) )
  656. {
  657. pCaps->m_NumVertexShaderConstants = min( 256, pCaps->m_NumVertexShaderConstants );
  658. }
  659. pCaps->m_NumBooleanVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
  660. pCaps->m_NumBooleanPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
  661. // This is a little misleading...this is really 16 int4 registers
  662. pCaps->m_NumIntegerVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
  663. pCaps->m_NumIntegerPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
  664. }
  665. if ( pCaps->m_SupportsPixelShaders )
  666. {
  667. if ( pCaps->m_SupportsPixelShaders_2_0 )
  668. {
  669. pCaps->m_NumPixelShaderConstants = 32;
  670. }
  671. else
  672. {
  673. pCaps->m_NumPixelShaderConstants = 8;
  674. }
  675. }
  676. else
  677. {
  678. pCaps->m_NumPixelShaderConstants = 0;
  679. }
  680. pCaps->m_SupportsHardwareLighting = (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0;
  681. pCaps->m_MaxNumLights = caps.MaxActiveLights;
  682. if ( pCaps->m_MaxNumLights > MAX_NUM_LIGHTS )
  683. {
  684. pCaps->m_MaxNumLights = MAX_NUM_LIGHTS;
  685. }
  686. if ( IsOpenGL() )
  687. {
  688. // Set according to control flow bit on OpenGL
  689. pCaps->m_MaxNumLights = MIN( pCaps->m_MaxNumLights, ( pCaps->m_bSupportsStaticControlFlow && pCaps->m_SupportsPixelShaders_2_b ) ? MAX_NUM_LIGHTS : ( MAX_NUM_LIGHTS - 2 ) );
  690. }
  691. if ( pCaps->m_bSoftwareVertexProcessing )
  692. {
  693. pCaps->m_SupportsHardwareLighting = true;
  694. pCaps->m_MaxNumLights = 2;
  695. }
  696. pCaps->m_MaxTextureWidth = caps.MaxTextureWidth;
  697. pCaps->m_MaxTextureHeight = caps.MaxTextureHeight;
  698. pCaps->m_MaxTextureDepth = caps.MaxVolumeExtent ? caps.MaxVolumeExtent : 1;
  699. pCaps->m_MaxTextureAspectRatio = caps.MaxTextureAspectRatio;
  700. if ( pCaps->m_MaxTextureAspectRatio == 0 )
  701. {
  702. pCaps->m_MaxTextureAspectRatio = max( pCaps->m_MaxTextureWidth, pCaps->m_MaxTextureHeight);
  703. }
  704. pCaps->m_MaxPrimitiveCount = caps.MaxPrimitiveCount;
  705. pCaps->m_MaxBlendMatrices = caps.MaxVertexBlendMatrices;
  706. pCaps->m_MaxBlendMatrixIndices = caps.MaxVertexBlendMatrixIndex;
  707. bool addSupported = (caps.TextureOpCaps & D3DTEXOPCAPS_ADD) != 0;
  708. bool modSupported = (caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE2X) != 0;
  709. pCaps->m_bNeedsATICentroidHack = false;
  710. pCaps->m_bDisableShaderOptimizations = false;
  711. pCaps->m_SupportsMipmapping = true;
  712. pCaps->m_SupportsOverbright = true;
  713. // Thank you to all you driver writers who actually correctly return caps
  714. if ( !modSupported || !addSupported )
  715. {
  716. Assert( 0 );
  717. pCaps->m_SupportsOverbright = false;
  718. }
  719. // Check if ZBias and SlopeScaleDepthBias are supported. .if not, tweak the projection matrix instead
  720. // for polyoffset.
  721. pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported =
  722. ( ( caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0 ) &&
  723. ( ( caps.RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS ) != 0 );
  724. if ( IsX360() )
  725. {
  726. // driver lies, force it
  727. pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported = true;
  728. }
  729. // Spheremapping supported?
  730. pCaps->m_bSupportsSpheremapping = (caps.VertexProcessingCaps & D3DVTXPCAPS_TEXGEN_SPHEREMAP) != 0;
  731. // How many user clip planes?
  732. pCaps->m_MaxUserClipPlanes = caps.MaxUserClipPlanes;
  733. if ( CommandLine()->CheckParm( "-nouserclip" ) /* || (IsOpenGL() && (!CommandLine()->FindParm("-glslmode"))) || r_emulategl.GetBool() */ )
  734. {
  735. // rbarris 03Feb10: this now ignores POSIX / -glslmode / r_emulategl because we're defaulting GLSL mode "on".
  736. // so this will mean that the engine will always ask for user clip planes.
  737. // this will misbehave under ARB mode, since ARB shaders won't respect that state.
  738. // it's difficult to make this fluid without teaching the engine about a cap that could change during run.
  739. pCaps->m_MaxUserClipPlanes = 0;
  740. }
  741. if ( pCaps->m_MaxUserClipPlanes > MAXUSERCLIPPLANES )
  742. {
  743. pCaps->m_MaxUserClipPlanes = MAXUSERCLIPPLANES;
  744. }
  745. pCaps->m_FakeSRGBWrite = false;
  746. pCaps->m_CanDoSRGBReadFromRTs = true;
  747. pCaps->m_bSupportsGLMixedSizeTargets = false;
  748. #ifdef DX_TO_GL_ABSTRACTION
  749. // using #if because we're referencing fields in the RHS which don't exist in Windows headers for the caps9 struct
  750. pCaps->m_FakeSRGBWrite = caps.FakeSRGBWrite != 0;
  751. pCaps->m_CanDoSRGBReadFromRTs = caps.CanDoSRGBReadFromRTs != 0;
  752. pCaps->m_bSupportsGLMixedSizeTargets = caps.MixedSizeTargets != 0;
  753. #endif
  754. // Query for SRGB support as needed for our DX 9 stuff
  755. if ( IsPC() || !IsX360() )
  756. {
  757. pCaps->m_SupportsSRGB = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_TEXTURE, D3DFMT_DXT1 ) == S_OK);
  758. if ( pCaps->m_SupportsSRGB )
  759. {
  760. pCaps->m_SupportsSRGB = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8 ) == S_OK);
  761. }
  762. }
  763. else
  764. {
  765. // 360 does support it, but is queried in the wrong manner, so force it
  766. pCaps->m_SupportsSRGB = true;
  767. }
  768. if ( CommandLine()->CheckParm( "-nosrgb" ) )
  769. {
  770. pCaps->m_SupportsSRGB = false;
  771. }
  772. pCaps->m_bSupportsVertexTextures = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8,
  773. D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R32F ) == S_OK );
  774. if ( IsOpenGL() )
  775. {
  776. pCaps->m_bSupportsVertexTextures = false;
  777. }
  778. // FIXME: vs30 has a fixed setting here at 4.
  779. // Future hardware will need some other way of computing this.
  780. pCaps->m_nVertexTextureCount = pCaps->m_bSupportsVertexTextures ? 4 : 0;
  781. // FIXME: How do I actually compute this?
  782. pCaps->m_nMaxVertexTextureDimension = pCaps->m_bSupportsVertexTextures ? 4096 : 0;
  783. // Does the device support filterable int16 textures?
  784. bool bSupportsInteger16Textures =
  785. ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
  786. D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER,
  787. D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16 ) == S_OK );
  788. // Does the device support filterable fp16 textures?
  789. bool bSupportsFloat16Textures =
  790. ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
  791. D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER,
  792. D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F ) == S_OK );
  793. // Does the device support blendable fp16 render targets?
  794. bool bSupportsFloat16RenderTargets =
  795. ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
  796. D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING | D3DUSAGE_RENDERTARGET,
  797. D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F ) == S_OK );
  798. // Essentially a proxy for a DX10 device running DX9 code path
  799. pCaps->m_bSupportsFloat32RenderTargets = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
  800. D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING | D3DUSAGE_RENDERTARGET,
  801. D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F ) == S_OK );
  802. pCaps->m_bFogColorSpecifiedInLinearSpace = false;
  803. pCaps->m_bFogColorAlwaysLinearSpace = false;
  804. // Assume not DX10. Check below.
  805. pCaps->m_bDX10Card = false;
  806. pCaps->m_bDX10Blending = false;
  807. if ( IsOpenGL() && ( pCaps->m_VendorID == 1 ) )
  808. {
  809. // Linux/Win OpenGL - always assume the device supports DX10 style blending
  810. pCaps->m_bFogColorAlwaysLinearSpace = true;
  811. pCaps->m_bDX10Card = true;
  812. pCaps->m_bDX10Blending = true;
  813. }
  814. // NVidia wants fog color to be specified in linear space
  815. if ( IsPC() && pCaps->m_SupportsSRGB )
  816. {
  817. if ( pCaps->m_VendorID == VENDORID_NVIDIA )
  818. {
  819. pCaps->m_bFogColorSpecifiedInLinearSpace = true;
  820. if ( IsOpenGL() )
  821. {
  822. // If we're not the Quadro 4500 or GeForce 7x000, we're an NVIDIA DX10 part on MacOS
  823. if ( !( (pCaps->m_DeviceID == 0x009d) || ( (pCaps->m_DeviceID >= 0x0391) && (pCaps->m_DeviceID <= 0x0395) ) ) )
  824. {
  825. pCaps->m_bFogColorAlwaysLinearSpace = true;
  826. pCaps->m_bDX10Card = true;
  827. pCaps->m_bDX10Blending = true;
  828. }
  829. }
  830. else
  831. {
  832. // On G80 and later, always specify in linear space
  833. if ( pCaps->m_bSupportsFloat32RenderTargets )
  834. {
  835. pCaps->m_bFogColorAlwaysLinearSpace = true;
  836. pCaps->m_bDX10Card = true;
  837. pCaps->m_bDX10Blending = true;
  838. }
  839. }
  840. }
  841. else if ( pCaps->m_VendorID == VENDORID_ATI )
  842. {
  843. if ( IsOpenGL() )
  844. {
  845. // If we're not a Radeon X1x00 (device IDs in this range), we're a DX10 chip
  846. if ( !( (pCaps->m_DeviceID >= 0x7109) && (pCaps->m_DeviceID <= 0x7291) ) )
  847. {
  848. pCaps->m_bFogColorSpecifiedInLinearSpace = true;
  849. pCaps->m_bFogColorAlwaysLinearSpace = true;
  850. pCaps->m_bDX10Card = true;
  851. pCaps->m_bDX10Blending = true;
  852. }
  853. }
  854. else
  855. {
  856. // Check for DX10 part
  857. pCaps->m_bDX10Card = pCaps->m_SupportsShaderModel_3_0 &&
  858. ( pCaps->m_MaxVertexShader30InstructionSlots > 1024 ) &&
  859. ( pCaps->m_MaxPixelShader30InstructionSlots > 512 ) ;
  860. // On ATI, DX10 card means DX10 blending
  861. pCaps->m_bDX10Blending = pCaps->m_bDX10Card;
  862. if( pCaps->m_bDX10Blending )
  863. {
  864. pCaps->m_bFogColorSpecifiedInLinearSpace = true;
  865. pCaps->m_bFogColorAlwaysLinearSpace = true;
  866. }
  867. }
  868. }
  869. else if ( pCaps->m_VendorID == VENDORID_INTEL )
  870. {
  871. // Intel does not have performant vertex textures
  872. pCaps->m_bDX10Card = false;
  873. // Intel supports DX10 SRGB on Broadwater and better
  874. // The two checks are for devices from GMA generation (0x29A2-0x2A43) and HD graphics (0x0042-0x2500)
  875. pCaps->m_bDX10Blending = ( ( pCaps->m_DeviceID >= 0x29A2 ) && ( pCaps->m_DeviceID <= 0x2A43 ) ) ||
  876. ( ( pCaps->m_DeviceID >= 0x0042 ) && ( pCaps->m_DeviceID <= 0x2500 ) );
  877. if( pCaps->m_bDX10Blending )
  878. {
  879. pCaps->m_bFogColorSpecifiedInLinearSpace = true;
  880. pCaps->m_bFogColorAlwaysLinearSpace = true;
  881. }
  882. }
  883. }
  884. // Do we have everything necessary to run with integer HDR? Note that
  885. // even if we don't support integer 16-bit/component textures, we
  886. // can still run in this mode if fp16 textures are supported.
  887. bool bSupportsIntegerHDR = pCaps->m_SupportsPixelShaders_2_0 &&
  888. pCaps->m_SupportsVertexShaders_2_0 &&
  889. // (caps.Caps3 & D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD) &&
  890. // (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) &&
  891. ( bSupportsInteger16Textures || bSupportsFloat16Textures ) &&
  892. pCaps->m_SupportsSRGB;
  893. // Do we have everything necessary to run with float HDR?
  894. bool bSupportsFloatHDR = pCaps->m_SupportsShaderModel_3_0 &&
  895. // (caps.Caps3 & D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD) &&
  896. // (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) &&
  897. bSupportsFloat16Textures &&
  898. bSupportsFloat16RenderTargets &&
  899. pCaps->m_SupportsSRGB &&
  900. !IsX360();
  901. pCaps->m_MaxHDRType = HDR_TYPE_NONE;
  902. if ( bSupportsFloatHDR )
  903. pCaps->m_MaxHDRType = HDR_TYPE_FLOAT;
  904. else
  905. if ( bSupportsIntegerHDR )
  906. pCaps->m_MaxHDRType = HDR_TYPE_INTEGER;
  907. if ( bSupportsFloatHDR && ( mat_hdr_level.GetInt() == 3 ) )
  908. {
  909. pCaps->m_HDRType = HDR_TYPE_FLOAT;
  910. }
  911. else if ( bSupportsIntegerHDR )
  912. {
  913. pCaps->m_HDRType = HDR_TYPE_INTEGER;
  914. }
  915. else
  916. {
  917. pCaps->m_HDRType = HDR_TYPE_NONE;
  918. }
  919. pCaps->m_bColorOnSecondStream = caps.MaxStreams > 1;
  920. pCaps->m_bSupportsStreamOffset = ( ( caps.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET ) && // Tie these caps together since we want to filter out
  921. pCaps->m_SupportsPixelShaders_2_0 ); // any DX8 parts which export D3DDEVCAPS2_STREAMOFFSET
  922. pCaps->m_flMinGammaControlPoint = 0.0f;
  923. pCaps->m_flMaxGammaControlPoint = 65535.0f;
  924. pCaps->m_nGammaControlPointCount = 256;
  925. // Compute the effective DX support level based on all the other caps
  926. ComputeDXSupportLevel( *pCaps );
  927. int nCmdlineMaxDXLevel = CommandLine()->ParmValue( "-maxdxlevel", 0 );
  928. if ( IsOpenGL() && ( nCmdlineMaxDXLevel > 0 ) )
  929. {
  930. // Prevent customers from slamming us below DX level 90 in OpenGL mode.
  931. nCmdlineMaxDXLevel = MAX( nCmdlineMaxDXLevel, 90 );
  932. }
  933. if( nCmdlineMaxDXLevel > 0 )
  934. {
  935. pCaps->m_nMaxDXSupportLevel = min( pCaps->m_nMaxDXSupportLevel, nCmdlineMaxDXLevel );
  936. }
  937. pCaps->m_nDXSupportLevel = pCaps->m_nMaxDXSupportLevel;
  938. int nModelIndex = pCaps->m_nDXSupportLevel < 90 ? VERTEX_SHADER_MODEL - 10 : VERTEX_SHADER_MODEL;
  939. pCaps->m_MaxVertexShaderBlendMatrices = (pCaps->m_NumVertexShaderConstants - nModelIndex) / 3;
  940. if ( pCaps->m_MaxVertexShaderBlendMatrices > NUM_MODEL_TRANSFORMS )
  941. {
  942. pCaps->m_MaxVertexShaderBlendMatrices = NUM_MODEL_TRANSFORMS;
  943. }
  944. CheckBorderColorSupport( pCaps, nAdapter );
  945. // This may get more complex if we start using multiple flavors of compressed vertex - for now it's "on or off"
  946. pCaps->m_SupportsCompressedVertices = ( pCaps->m_nDXSupportLevel >= 90 ) && ( pCaps->m_CanDoSRGBReadFromRTs ) ? VERTEX_COMPRESSION_ON : VERTEX_COMPRESSION_NONE;
  947. if ( CommandLine()->CheckParm( "-no_compressed_verts" ) ) // m_CanDoSRGBReadFromRTs limits us to Snow Leopard or later on OSX
  948. {
  949. pCaps->m_SupportsCompressedVertices = VERTEX_COMPRESSION_NONE;
  950. }
  951. // Various vendor-dependent checks...
  952. CheckVendorDependentAlphaToCoverage( pCaps, nAdapter );
  953. CheckVendorDependentShadowMappingSupport( pCaps, nAdapter );
  954. // If we're not on a 3.0 part, these values are more appropriate (X800 & X850 parts from ATI do shadow mapping but not 3.0 )
  955. if ( !IsOpenGL() )
  956. {
  957. if ( !pCaps->m_SupportsShaderModel_3_0 )
  958. {
  959. mat_slopescaledepthbias_shadowmap.SetValue( 5.9f );
  960. mat_depthbias_shadowmap.SetValue( 0.003f );
  961. }
  962. }
  963. if( pCaps->m_MaxUserClipPlanes == 0 )
  964. {
  965. pCaps->m_UseFastClipping = true;
  966. }
  967. pCaps->m_MaxSimultaneousRenderTargets = caps.NumSimultaneousRTs;
  968. return true;
  969. }
  970. //-----------------------------------------------------------------------------
  971. // Compute the effective DX support level based on all the other caps
  972. //-----------------------------------------------------------------------------
  973. void CShaderDeviceMgrDx8::ComputeDXSupportLevel( HardwareCaps_t &caps )
  974. {
  975. // NOTE: Support level is actually DX level * 10 + subversion
  976. // So, 70 = DX7, 80 = DX8, 81 = DX8 w/ 1.4 pixel shaders
  977. // 90 = DX9 w/ 2.0 pixel shaders
  978. // 95 = DX9 w/ 3.0 pixel shaders and vertex textures
  979. // 98 = DX9 XBox360
  980. // NOTE: 82 = NVidia nv3x cards, which can't run dx9 fast
  981. // FIXME: Improve this!! There should be a whole list of features
  982. // we require in order to be considered a DX7 board, DX8 board, etc.
  983. if ( IsX360() )
  984. {
  985. caps.m_nMaxDXSupportLevel = 98;
  986. return;
  987. }
  988. bool bIsOpenGL = IsOpenGL();
  989. if ( caps.m_SupportsShaderModel_3_0 && !bIsOpenGL ) // Note that we don't tie vertex textures to 30 shaders anymore
  990. {
  991. caps.m_nMaxDXSupportLevel = 95;
  992. return;
  993. }
  994. // NOTE: sRGB is currently required for DX90 because it isn't doing
  995. // gamma correctly if that feature doesn't exist
  996. if ( caps.m_SupportsVertexShaders_2_0 && caps.m_SupportsPixelShaders_2_0 && caps.m_SupportsSRGB )
  997. {
  998. caps.m_nMaxDXSupportLevel = 90;
  999. return;
  1000. }
  1001. if ( caps.m_SupportsPixelShaders && caps.m_SupportsVertexShaders )// && caps.m_bColorOnSecondStream)
  1002. {
  1003. if (caps.m_SupportsPixelShaders_1_4)
  1004. {
  1005. caps.m_nMaxDXSupportLevel = 81;
  1006. return;
  1007. }
  1008. caps.m_nMaxDXSupportLevel = 80;
  1009. return;
  1010. }
  1011. if( caps.m_SupportsCubeMaps && ( caps.m_MaxBlendMatrices >= 2 ) )
  1012. {
  1013. caps.m_nMaxDXSupportLevel = 70;
  1014. return;
  1015. }
  1016. if ( ( caps.m_NumSamplers >= 2) && caps.m_SupportsMipmapping )
  1017. {
  1018. caps.m_nMaxDXSupportLevel = 60;
  1019. return;
  1020. }
  1021. Assert( 0 );
  1022. // we don't support this!
  1023. caps.m_nMaxDXSupportLevel = 50;
  1024. }
  1025. //-----------------------------------------------------------------------------
  1026. // Gets the number of adapters...
  1027. //-----------------------------------------------------------------------------
  1028. int CShaderDeviceMgrDx8::GetAdapterCount() const
  1029. {
  1030. // FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
  1031. const_cast<CShaderDeviceMgrDx8*>( this )->InitAdapterInfo();
  1032. return m_Adapters.Count();
  1033. }
  1034. //-----------------------------------------------------------------------------
  1035. // Returns info about each adapter
  1036. //-----------------------------------------------------------------------------
  1037. void CShaderDeviceMgrDx8::GetAdapterInfo( int nAdapter, MaterialAdapterInfo_t& info ) const
  1038. {
  1039. // FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
  1040. const_cast<CShaderDeviceMgrDx8*>( this )->InitAdapterInfo();
  1041. Assert( ( nAdapter >= 0 ) && ( nAdapter < m_Adapters.Count() ) );
  1042. const HardwareCaps_t &caps = m_Adapters[ nAdapter ].m_ActualCaps;
  1043. memcpy( &info, &caps, sizeof(MaterialAdapterInfo_t) );
  1044. }
  1045. //-----------------------------------------------------------------------------
  1046. // Sets the adapter
  1047. //-----------------------------------------------------------------------------
  1048. bool CShaderDeviceMgrDx8::SetAdapter( int nAdapter, int nAdapterFlags )
  1049. {
  1050. LOCK_SHADERAPI();
  1051. // FIXME:
  1052. // g_pShaderDeviceDx8->m_bReadPixelsEnabled = (nAdapterFlags & MATERIAL_INIT_READ_PIXELS_ENABLED) != 0;
  1053. // Set up hardware information for this adapter...
  1054. g_pShaderDeviceDx8->m_DeviceType = (nAdapterFlags & MATERIAL_INIT_REFERENCE_RASTERIZER) ?
  1055. D3DDEVTYPE_REF : D3DDEVTYPE_HAL;
  1056. g_pShaderDeviceDx8->m_DisplayAdapter = nAdapter;
  1057. if ( g_pShaderDeviceDx8->m_DisplayAdapter >= (UINT)GetAdapterCount() )
  1058. {
  1059. g_pShaderDeviceDx8->m_DisplayAdapter = 0;
  1060. }
  1061. #ifdef NVPERFHUD
  1062. // hack for nvperfhud
  1063. g_pShaderDeviceDx8->m_DisplayAdapter = m_pD3D->GetAdapterCount() - 1;
  1064. g_pShaderDeviceDx8->m_DeviceType = D3DDEVTYPE_REF;
  1065. #endif
  1066. // backward compat
  1067. if ( !g_pShaderDeviceDx8->OnAdapterSet() )
  1068. return false;
  1069. // if ( !g_pShaderDeviceDx8->Init() )
  1070. // {
  1071. // Warning( "Unable to initialize dx8 device!\n" );
  1072. // return false;
  1073. // }
  1074. g_pShaderDevice = g_pShaderDeviceDx8;
  1075. return true;
  1076. }
  1077. //-----------------------------------------------------------------------------
  1078. // Returns the number of modes
  1079. //-----------------------------------------------------------------------------
  1080. int CShaderDeviceMgrDx8::GetModeCount( int nAdapter ) const
  1081. {
  1082. LOCK_SHADERAPI();
  1083. Assert( m_pD3D && (nAdapter < GetAdapterCount() ) );
  1084. #if !defined( _X360 )
  1085. // fixme - what format should I use here?
  1086. return m_pD3D->GetAdapterModeCount( nAdapter, D3DFMT_X8R8G8B8 );
  1087. #else
  1088. return 1; // Only one mode, which is the current mode set in the 360 dashboard. Going to fill it in with exactly what the 360 is set to.
  1089. #endif
  1090. }
  1091. //-----------------------------------------------------------------------------
  1092. // Returns mode information..
  1093. //-----------------------------------------------------------------------------
  1094. void CShaderDeviceMgrDx8::GetModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter, int nMode ) const
  1095. {
  1096. Assert( pInfo->m_nVersion == SHADER_DISPLAY_MODE_VERSION );
  1097. LOCK_SHADERAPI();
  1098. Assert( m_pD3D && (nAdapter < GetAdapterCount() ) );
  1099. Assert( nMode < GetModeCount( nAdapter ) );
  1100. #if !defined( _X360 )
  1101. HRESULT hr;
  1102. D3DDISPLAYMODE d3dInfo;
  1103. // fixme - what format should I use here?
  1104. hr = D3D()->EnumAdapterModes( nAdapter, D3DFMT_X8R8G8B8, nMode, &d3dInfo );
  1105. Assert( !FAILED(hr) );
  1106. pInfo->m_nWidth = d3dInfo.Width;
  1107. pInfo->m_nHeight = d3dInfo.Height;
  1108. pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( d3dInfo.Format );
  1109. pInfo->m_nRefreshRateNumerator = d3dInfo.RefreshRate;
  1110. pInfo->m_nRefreshRateDenominator = 1;
  1111. #else
  1112. pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( D3DFMT_X8R8G8B8 );
  1113. pInfo->m_nRefreshRateNumerator = 60;
  1114. pInfo->m_nRefreshRateDenominator = 1;
  1115. pInfo->m_nWidth = GetSystemMetrics( SM_CXSCREEN );
  1116. pInfo->m_nHeight = GetSystemMetrics( SM_CYSCREEN );
  1117. #endif
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Returns the current mode information for an adapter
  1121. //-----------------------------------------------------------------------------
  1122. void CShaderDeviceMgrDx8::GetCurrentModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter ) const
  1123. {
  1124. Assert( pInfo->m_nVersion == SHADER_DISPLAY_MODE_VERSION );
  1125. LOCK_SHADERAPI();
  1126. Assert( D3D() );
  1127. HRESULT hr;
  1128. D3DDISPLAYMODE mode = { 0 };
  1129. #if !defined( _X360 )
  1130. hr = D3D()->GetAdapterDisplayMode( nAdapter, &mode );
  1131. Assert( !FAILED(hr) );
  1132. #else
  1133. if ( !g_pD3DDevice )
  1134. {
  1135. // the console has no prior display or mode until its created
  1136. mode.Width = GetSystemMetrics( SM_CXSCREEN );
  1137. mode.Height = GetSystemMetrics( SM_CYSCREEN );
  1138. mode.RefreshRate = 60;
  1139. mode.Format = D3DFMT_X8R8G8B8;
  1140. }
  1141. else
  1142. {
  1143. hr = g_pD3DDevice->GetDisplayMode( 0, &mode );
  1144. Assert( !FAILED(hr) );
  1145. }
  1146. #endif
  1147. pInfo->m_nWidth = mode.Width;
  1148. pInfo->m_nHeight = mode.Height;
  1149. pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( mode.Format );
  1150. pInfo->m_nRefreshRateNumerator = mode.RefreshRate;
  1151. pInfo->m_nRefreshRateDenominator = 1;
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. // Sets the video mode
  1155. //-----------------------------------------------------------------------------
  1156. CreateInterfaceFn CShaderDeviceMgrDx8::SetMode( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode )
  1157. {
  1158. LOCK_SHADERAPI();
  1159. Assert( nAdapter < GetAdapterCount() );
  1160. int nDXLevel = mode.m_nDXLevel != 0 ? mode.m_nDXLevel : m_Adapters[nAdapter].m_ActualCaps.m_nDXSupportLevel;
  1161. if ( m_bObeyDxCommandlineOverride )
  1162. {
  1163. nDXLevel = CommandLine()->ParmValue( "-dxlevel", nDXLevel );
  1164. m_bObeyDxCommandlineOverride = false;
  1165. }
  1166. if ( nDXLevel > m_Adapters[nAdapter].m_ActualCaps.m_nMaxDXSupportLevel )
  1167. {
  1168. nDXLevel = m_Adapters[nAdapter].m_ActualCaps.m_nMaxDXSupportLevel;
  1169. }
  1170. nDXLevel = GetClosestActualDXLevel( nDXLevel );
  1171. if ( nDXLevel >= 100 )
  1172. return NULL;
  1173. bool bReacquireResourcesNeeded = false;
  1174. if ( g_pShaderDevice )
  1175. {
  1176. bReacquireResourcesNeeded = IsPC();
  1177. g_pShaderDevice->ReleaseResources();
  1178. }
  1179. if ( g_pShaderAPI )
  1180. {
  1181. g_pShaderAPI->OnDeviceShutdown();
  1182. g_pShaderAPI = NULL;
  1183. }
  1184. if ( g_pShaderDevice )
  1185. {
  1186. g_pShaderDevice->ShutdownDevice();
  1187. g_pShaderDevice = NULL;
  1188. }
  1189. g_pShaderShadow = NULL;
  1190. ShaderDeviceInfo_t adjustedMode = mode;
  1191. adjustedMode.m_nDXLevel = nDXLevel;
  1192. if ( !g_pShaderDeviceDx8->InitDevice( hWnd, nAdapter, adjustedMode ) )
  1193. return NULL;
  1194. if ( !g_pShaderAPIDX8->OnDeviceInit() )
  1195. return NULL;
  1196. g_pShaderDevice = g_pShaderDeviceDx8;
  1197. g_pShaderAPI = g_pShaderAPIDX8;
  1198. g_pShaderShadow = g_pShaderShadowDx8;
  1199. if ( bReacquireResourcesNeeded )
  1200. {
  1201. g_pShaderDevice->ReacquireResources();
  1202. }
  1203. return ShaderInterfaceFactory;
  1204. }
  1205. //-----------------------------------------------------------------------------
  1206. // Validates the mode...
  1207. //-----------------------------------------------------------------------------
  1208. bool CShaderDeviceMgrDx8::ValidateMode( int nAdapter, const ShaderDeviceInfo_t &info ) const
  1209. {
  1210. if ( nAdapter >= (int)D3D()->GetAdapterCount() )
  1211. return false;
  1212. ShaderDisplayMode_t displayMode;
  1213. if ( info.m_bWindowed )
  1214. {
  1215. // windowed mode always appears on the primary display, so we should use that adapter's
  1216. // settings
  1217. GetCurrentModeInfo( &displayMode, 0 );
  1218. // make sure the window fits within the current video mode
  1219. if ( ( info.m_DisplayMode.m_nWidth > displayMode.m_nWidth ) ||
  1220. ( info.m_DisplayMode.m_nHeight > displayMode.m_nHeight ) )
  1221. return false;
  1222. }
  1223. else
  1224. {
  1225. GetCurrentModeInfo( &displayMode, nAdapter );
  1226. }
  1227. // Make sure the image format requested is valid
  1228. ImageFormat backBufferFormat = FindNearestSupportedBackBufferFormat( nAdapter,
  1229. DX8_DEVTYPE, displayMode.m_Format, info.m_DisplayMode.m_Format, info.m_bWindowed );
  1230. return ( backBufferFormat != IMAGE_FORMAT_UNKNOWN );
  1231. }
  1232. //-----------------------------------------------------------------------------
  1233. // Returns the amount of video memory in bytes for a particular adapter
  1234. //-----------------------------------------------------------------------------
  1235. int CShaderDeviceMgrDx8::GetVidMemBytes( int nAdapter ) const
  1236. {
  1237. #if defined( _X360 )
  1238. return 256*1024*1024;
  1239. #elif defined (DX_TO_GL_ABSTRACTION)
  1240. D3DADAPTER_IDENTIFIER9 devIndentifier;
  1241. D3D()->GetAdapterIdentifier( nAdapter, D3DENUM_WHQL_LEVEL, &devIndentifier );
  1242. return devIndentifier.VideoMemory;
  1243. #else
  1244. // FIXME: This currently ignores the adapter
  1245. uint64 nBytes = ::GetVidMemBytes();
  1246. if ( nBytes > INT_MAX )
  1247. return INT_MAX;
  1248. return nBytes;
  1249. #endif
  1250. }
  1251. //-----------------------------------------------------------------------------
  1252. //
  1253. // Shader device
  1254. //
  1255. //-----------------------------------------------------------------------------
  1256. #if 0
  1257. // FIXME: Enable after I've separated it out from shaderapidx8 a little better
  1258. static CShaderDeviceDx8 s_ShaderDeviceDX8;
  1259. CShaderDeviceDx8* g_pShaderDeviceDx8 = &s_ShaderDeviceDX8;
  1260. #endif
  1261. //-----------------------------------------------------------------------------
  1262. // Constructor, destructor
  1263. //-----------------------------------------------------------------------------
  1264. CShaderDeviceDx8::CShaderDeviceDx8()
  1265. {
  1266. g_pD3DDevice = NULL;
  1267. for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
  1268. {
  1269. m_pFrameSyncQueryObject[i] = NULL;
  1270. m_bQueryIssued[i] = false;
  1271. }
  1272. m_pFrameSyncTexture = NULL;
  1273. m_bQueuedDeviceLost = false;
  1274. m_DeviceState = DEVICE_STATE_OK;
  1275. m_bOtherAppInitializing = false;
  1276. m_IsResizing = false;
  1277. m_bPendingVideoModeChange = false;
  1278. m_DeviceSupportsCreateQuery = -1;
  1279. m_bUsingStencil = false;
  1280. m_bResourcesReleased = false;
  1281. m_iStencilBufferBits = 0;
  1282. m_NonInteractiveRefresh.m_Mode = MATERIAL_NON_INTERACTIVE_MODE_NONE;
  1283. m_NonInteractiveRefresh.m_pVertexShader = NULL;
  1284. m_NonInteractiveRefresh.m_pPixelShader = NULL;
  1285. m_NonInteractiveRefresh.m_pPixelShaderStartup = NULL;
  1286. m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 = NULL;
  1287. m_NonInteractiveRefresh.m_pVertexDecl = NULL;
  1288. m_NonInteractiveRefresh.m_nPacifierFrame = 0;
  1289. m_numReleaseResourcesRefCount = 0;
  1290. }
  1291. CShaderDeviceDx8::~CShaderDeviceDx8()
  1292. {
  1293. }
  1294. //-----------------------------------------------------------------------------
  1295. // Computes device creation paramters
  1296. //-----------------------------------------------------------------------------
  1297. static DWORD ComputeDeviceCreationFlags( D3DCAPS& caps, bool bSoftwareVertexProcessing )
  1298. {
  1299. // Find out what type of device to make
  1300. bool bPureDeviceSupported = (caps.DevCaps & D3DDEVCAPS_PUREDEVICE) != 0;
  1301. DWORD nDeviceCreationFlags;
  1302. if ( !bSoftwareVertexProcessing )
  1303. {
  1304. nDeviceCreationFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1305. if ( bPureDeviceSupported )
  1306. {
  1307. nDeviceCreationFlags |= D3DCREATE_PUREDEVICE;
  1308. }
  1309. }
  1310. else
  1311. {
  1312. nDeviceCreationFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1313. }
  1314. nDeviceCreationFlags |= D3DCREATE_FPU_PRESERVE;
  1315. #ifdef _X360
  1316. nDeviceCreationFlags |= D3DCREATE_BUFFER_2_FRAMES;
  1317. #endif
  1318. return nDeviceCreationFlags;
  1319. }
  1320. //-----------------------------------------------------------------------------
  1321. // Computes the supersample flags
  1322. //-----------------------------------------------------------------------------
  1323. D3DMULTISAMPLE_TYPE CShaderDeviceDx8::ComputeMultisampleType( int nSampleCount )
  1324. {
  1325. switch (nSampleCount)
  1326. {
  1327. #if !defined( _X360 )
  1328. case 2: return D3DMULTISAMPLE_2_SAMPLES;
  1329. case 3: return D3DMULTISAMPLE_3_SAMPLES;
  1330. case 4: return D3DMULTISAMPLE_4_SAMPLES;
  1331. case 5: return D3DMULTISAMPLE_5_SAMPLES;
  1332. case 6: return D3DMULTISAMPLE_6_SAMPLES;
  1333. case 7: return D3DMULTISAMPLE_7_SAMPLES;
  1334. case 8: return D3DMULTISAMPLE_8_SAMPLES;
  1335. case 9: return D3DMULTISAMPLE_9_SAMPLES;
  1336. case 10: return D3DMULTISAMPLE_10_SAMPLES;
  1337. case 11: return D3DMULTISAMPLE_11_SAMPLES;
  1338. case 12: return D3DMULTISAMPLE_12_SAMPLES;
  1339. case 13: return D3DMULTISAMPLE_13_SAMPLES;
  1340. case 14: return D3DMULTISAMPLE_14_SAMPLES;
  1341. case 15: return D3DMULTISAMPLE_15_SAMPLES;
  1342. case 16: return D3DMULTISAMPLE_16_SAMPLES;
  1343. #else
  1344. case 2: return D3DMULTISAMPLE_2_SAMPLES;
  1345. case 4: return D3DMULTISAMPLE_4_SAMPLES;
  1346. #endif
  1347. default:
  1348. case 0:
  1349. case 1:
  1350. return D3DMULTISAMPLE_NONE;
  1351. }
  1352. }
  1353. //-----------------------------------------------------------------------------
  1354. // Sets the present parameters
  1355. //-----------------------------------------------------------------------------
  1356. void CShaderDeviceDx8::SetPresentParameters( void* hWnd, int nAdapter, const ShaderDeviceInfo_t &info )
  1357. {
  1358. ShaderDisplayMode_t mode;
  1359. g_pShaderDeviceMgr->GetCurrentModeInfo( &mode, nAdapter );
  1360. HRESULT hr;
  1361. ZeroMemory( &m_PresentParameters, sizeof(m_PresentParameters) );
  1362. m_PresentParameters.Windowed = info.m_bWindowed;
  1363. m_PresentParameters.SwapEffect = info.m_bUsingMultipleWindows ? D3DSWAPEFFECT_COPY : D3DSWAPEFFECT_DISCARD;
  1364. // for 360, we want to create it ourselves for hierarchical z support
  1365. m_PresentParameters.EnableAutoDepthStencil = IsX360() ? FALSE : TRUE;
  1366. // What back-buffer format should we use?
  1367. ImageFormat backBufferFormat = FindNearestSupportedBackBufferFormat( nAdapter,
  1368. DX8_DEVTYPE, m_AdapterFormat, info.m_DisplayMode.m_Format, info.m_bWindowed );
  1369. // What depth format should we use?
  1370. m_bUsingStencil = info.m_bUseStencil;
  1371. if ( info.m_nDXLevel >= 80 )
  1372. {
  1373. // always stencil for dx9/hdr
  1374. m_bUsingStencil = true;
  1375. }
  1376. #if defined( _X360 )
  1377. D3DFORMAT nDepthFormat = ReverseDepthOnX360() ? D3DFMT_D24FS8 : D3DFMT_D24S8;
  1378. #else
  1379. D3DFORMAT nDepthFormat = m_bUsingStencil ? D3DFMT_D24S8 : D3DFMT_D24X8;
  1380. #endif
  1381. m_PresentParameters.AutoDepthStencilFormat = FindNearestSupportedDepthFormat(
  1382. nAdapter, m_AdapterFormat, backBufferFormat, nDepthFormat );
  1383. m_PresentParameters.hDeviceWindow = (VD3DHWND)hWnd;
  1384. // store how many stencil buffer bits we have available with the depth/stencil buffer
  1385. switch( m_PresentParameters.AutoDepthStencilFormat )
  1386. {
  1387. case D3DFMT_D24S8:
  1388. m_iStencilBufferBits = 8;
  1389. break;
  1390. #if defined( _X360 )
  1391. case D3DFMT_D24FS8:
  1392. m_iStencilBufferBits = 8;
  1393. break;
  1394. #else
  1395. case D3DFMT_D24X4S4:
  1396. m_iStencilBufferBits = 4;
  1397. break;
  1398. case D3DFMT_D15S1:
  1399. m_iStencilBufferBits = 1;
  1400. break;
  1401. #endif
  1402. default:
  1403. m_iStencilBufferBits = 0;
  1404. m_bUsingStencil = false; //couldn't acquire a stencil buffer
  1405. };
  1406. if ( IsX360() || !info.m_bWindowed )
  1407. {
  1408. bool useDefault = ( info.m_DisplayMode.m_nWidth == 0 ) || ( info.m_DisplayMode.m_nHeight == 0 );
  1409. m_PresentParameters.BackBufferCount = 1;
  1410. m_PresentParameters.BackBufferWidth = useDefault ? mode.m_nWidth : info.m_DisplayMode.m_nWidth;
  1411. m_PresentParameters.BackBufferHeight = useDefault ? mode.m_nHeight : info.m_DisplayMode.m_nHeight;
  1412. m_PresentParameters.BackBufferFormat = ImageLoader::ImageFormatToD3DFormat( backBufferFormat );
  1413. #if defined( _X360 )
  1414. m_PresentParameters.FrontBufferFormat = D3DFMT_LE_X8R8G8B8;
  1415. #endif
  1416. if ( !info.m_bWaitForVSync || CommandLine()->FindParm( "-forcenovsync" ) )
  1417. {
  1418. m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1419. }
  1420. else
  1421. {
  1422. m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1423. }
  1424. m_PresentParameters.FullScreen_RefreshRateInHz = info.m_DisplayMode.m_nRefreshRateDenominator ?
  1425. info.m_DisplayMode.m_nRefreshRateNumerator / info.m_DisplayMode.m_nRefreshRateDenominator : D3DPRESENT_RATE_DEFAULT;
  1426. #if defined( _X360 )
  1427. XVIDEO_MODE videoMode;
  1428. XGetVideoMode( &videoMode );
  1429. // want 30 for 60Hz, and 25 for 50Hz (PAL)
  1430. int nNewFpsMax = ( ( int )( videoMode.RefreshRate + 0.5f ) ) >> 1;
  1431. // slam to either 30 or 25 so that we don't end up with any other cases.
  1432. if( nNewFpsMax < 26 )
  1433. {
  1434. nNewFpsMax = 25;
  1435. }
  1436. else
  1437. {
  1438. nNewFpsMax = 30;
  1439. }
  1440. DevMsg( "*******Monitor refresh is %f, setting fps_max to %d*********\n", videoMode.RefreshRate, nNewFpsMax );
  1441. ConVarRef fps_max( "fps_max" );
  1442. fps_max.SetValue( nNewFpsMax );
  1443. // setup hardware scaling - should be native 720p upsampling to 1080i
  1444. if ( info.m_bScaleToOutputResolution )
  1445. {
  1446. m_PresentParameters.VideoScalerParameters.ScalerSourceRect.x2 = m_PresentParameters.BackBufferWidth;
  1447. m_PresentParameters.VideoScalerParameters.ScalerSourceRect.y2 = m_PresentParameters.BackBufferHeight;
  1448. m_PresentParameters.VideoScalerParameters.ScaledOutputWidth = videoMode.dwDisplayWidth;
  1449. m_PresentParameters.VideoScalerParameters.ScaledOutputHeight = videoMode.dwDisplayHeight;
  1450. DevMsg( "VIDEO SCALING: scaling from %dx%d to %dx%d\n", ( int )m_PresentParameters.BackBufferWidth, ( int )m_PresentParameters.BackBufferHeight,
  1451. ( int )videoMode.dwDisplayWidth, ( int )videoMode.dwDisplayHeight );
  1452. }
  1453. else
  1454. {
  1455. DevMsg( "VIDEO SCALING: No scaling: %dx%d\n", ( int )m_PresentParameters.BackBufferWidth, ( int )m_PresentParameters.BackBufferHeight );
  1456. }
  1457. #endif
  1458. }
  1459. else
  1460. {
  1461. // NJS: We are seeing a lot of time spent in present in some cases when this isn't set.
  1462. m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1463. if ( info.m_bResizing )
  1464. {
  1465. if ( info.m_bLimitWindowedSize &&
  1466. ( info.m_nWindowedSizeLimitWidth < mode.m_nWidth || info.m_nWindowedSizeLimitHeight < mode.m_nHeight ) )
  1467. {
  1468. // When using material system in windowed resizing apps, it's
  1469. // sometimes not a good idea to allocate stuff as big as the screen
  1470. // video cards can soo run out of resources
  1471. m_PresentParameters.BackBufferWidth = info.m_nWindowedSizeLimitWidth;
  1472. m_PresentParameters.BackBufferHeight = info.m_nWindowedSizeLimitHeight;
  1473. }
  1474. else
  1475. {
  1476. // When in resizing windowed mode,
  1477. // we want to allocate enough memory to deal with any resizing...
  1478. m_PresentParameters.BackBufferWidth = mode.m_nWidth;
  1479. m_PresentParameters.BackBufferHeight = mode.m_nHeight;
  1480. }
  1481. }
  1482. else
  1483. {
  1484. m_PresentParameters.BackBufferWidth = info.m_DisplayMode.m_nWidth;
  1485. m_PresentParameters.BackBufferHeight = info.m_DisplayMode.m_nHeight;
  1486. }
  1487. m_PresentParameters.BackBufferFormat = ImageLoader::ImageFormatToD3DFormat( backBufferFormat );
  1488. m_PresentParameters.BackBufferCount = 1;
  1489. }
  1490. if ( info.m_nAASamples > 0 && ( m_PresentParameters.SwapEffect == D3DSWAPEFFECT_DISCARD ) )
  1491. {
  1492. D3DMULTISAMPLE_TYPE multiSampleType = ComputeMultisampleType( info.m_nAASamples );
  1493. DWORD nQualityLevel;
  1494. // FIXME: Should we add the quality level to the ShaderAdapterMode_t struct?
  1495. // 16x on nVidia refers to CSAA or "Coverage Sampled Antialiasing"
  1496. const HardwareCaps_t &adapterCaps = g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter );
  1497. if ( ( info.m_nAASamples == 16 ) && ( adapterCaps.m_VendorID == VENDORID_NVIDIA ) )
  1498. {
  1499. multiSampleType = ComputeMultisampleType(4);
  1500. hr = D3D()->CheckDeviceMultiSampleType( nAdapter, DX8_DEVTYPE,
  1501. m_PresentParameters.BackBufferFormat, m_PresentParameters.Windowed,
  1502. multiSampleType, &nQualityLevel ); // 4x at highest quality level
  1503. if ( !FAILED( hr ) && ( nQualityLevel == 16 ) )
  1504. {
  1505. nQualityLevel = nQualityLevel - 1; // Highest quality level triggers 16x CSAA
  1506. }
  1507. else
  1508. {
  1509. nQualityLevel = 0; // No CSAA
  1510. }
  1511. }
  1512. else // Regular MSAA on any old vendor
  1513. {
  1514. hr = D3D()->CheckDeviceMultiSampleType( nAdapter, DX8_DEVTYPE,
  1515. m_PresentParameters.BackBufferFormat, m_PresentParameters.Windowed,
  1516. multiSampleType, &nQualityLevel );
  1517. nQualityLevel = 0;
  1518. }
  1519. if ( !FAILED( hr ) )
  1520. {
  1521. m_PresentParameters.MultiSampleType = multiSampleType;
  1522. m_PresentParameters.MultiSampleQuality = nQualityLevel;
  1523. }
  1524. }
  1525. else
  1526. {
  1527. m_PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
  1528. m_PresentParameters.MultiSampleQuality = 0;
  1529. }
  1530. }
  1531. //-----------------------------------------------------------------------------
  1532. // Initializes, shuts down the D3D device
  1533. //-----------------------------------------------------------------------------
  1534. bool CShaderDeviceDx8::InitDevice( void* hwnd, int nAdapter, const ShaderDeviceInfo_t &info )
  1535. {
  1536. //Debugger();
  1537. // good place to run some self tests.
  1538. //#if OSX
  1539. //{
  1540. // extern void GLMgrSelfTests( void );
  1541. // GLMgrSelfTests();
  1542. //}
  1543. //#endif
  1544. // windowed
  1545. if ( !CreateD3DDevice( (VD3DHWND)hwnd, nAdapter, info ) )
  1546. return false;
  1547. // Hook up our own windows proc to get at messages to tell us when
  1548. // other instances of the material system are trying to set the mode
  1549. InstallWindowHook( (VD3DHWND)m_hWnd );
  1550. return true;
  1551. }
  1552. void CShaderDeviceDx8::ShutdownDevice()
  1553. {
  1554. if ( IsPC() && IsActive() )
  1555. {
  1556. Dx9Device()->Release();
  1557. #ifdef STUBD3D
  1558. delete ( CStubD3DDevice * )Dx9Device();
  1559. #endif
  1560. g_pD3DDevice = NULL;
  1561. RemoveWindowHook( (VD3DHWND)m_hWnd );
  1562. m_hWnd = 0;
  1563. }
  1564. }
  1565. //-----------------------------------------------------------------------------
  1566. // Are we using graphics?
  1567. //-----------------------------------------------------------------------------
  1568. bool CShaderDeviceDx8::IsUsingGraphics() const
  1569. {
  1570. //*****LOCK_SHADERAPI();
  1571. return IsActive();
  1572. }
  1573. //-----------------------------------------------------------------------------
  1574. // Returns the current adapter in use
  1575. //-----------------------------------------------------------------------------
  1576. int CShaderDeviceDx8::GetCurrentAdapter() const
  1577. {
  1578. LOCK_SHADERAPI();
  1579. return m_DisplayAdapter;
  1580. }
  1581. //-----------------------------------------------------------------------------
  1582. // Returns the current adapter in use
  1583. //-----------------------------------------------------------------------------
  1584. char *CShaderDeviceDx8::GetDisplayDeviceName()
  1585. {
  1586. if( m_sDisplayDeviceName.IsEmpty() )
  1587. {
  1588. D3DADAPTER_IDENTIFIER9 ident;
  1589. // On Win10, this function is getting called with m_nAdapter still initialized to -1.
  1590. // It's failing, and m_sDisplayDeviceName has garbage, and tf2 fails to launch.
  1591. // To repro this, run "hl2.exe -dev -fullscreen -game tf" on Win10.
  1592. HRESULT hr = D3D()->GetAdapterIdentifier( Max( m_nAdapter, 0 ), 0, &ident );
  1593. if ( FAILED(hr) )
  1594. {
  1595. Assert( false );
  1596. ident.DeviceName[0] = 0;
  1597. }
  1598. m_sDisplayDeviceName = ident.DeviceName;
  1599. }
  1600. return m_sDisplayDeviceName.GetForModify();
  1601. }
  1602. //-----------------------------------------------------------------------------
  1603. // Use this to spew information about the 3D layer
  1604. //-----------------------------------------------------------------------------
  1605. void CShaderDeviceDx8::SpewDriverInfo() const
  1606. {
  1607. LOCK_SHADERAPI();
  1608. HRESULT hr;
  1609. D3DCAPS caps;
  1610. D3DADAPTER_IDENTIFIER9 ident;
  1611. RECORD_COMMAND( DX8_GET_DEVICE_CAPS, 0 );
  1612. RECORD_COMMAND( DX8_GET_ADAPTER_IDENTIFIER, 2 );
  1613. RECORD_INT( m_nAdapter );
  1614. RECORD_INT( 0 );
  1615. Dx9Device()->GetDeviceCaps( &caps );
  1616. hr = D3D()->GetAdapterIdentifier( m_nAdapter, D3DENUM_WHQL_LEVEL, &ident );
  1617. Warning("Shader API Driver Info:\n\nDriver : %s Version : %lld\n",
  1618. ident.Driver, ident.DriverVersion.QuadPart );
  1619. Warning("Driver Description : %s\n", ident.Description );
  1620. Warning("Chipset version %d %d %d %d\n\n",
  1621. ident.VendorId, ident.DeviceId, ident.SubSysId, ident.Revision );
  1622. ShaderDisplayMode_t mode;
  1623. g_pShaderDeviceMgr->GetCurrentModeInfo( &mode, m_nAdapter );
  1624. Warning("Display mode : %d x %d (%s)\n",
  1625. mode.m_nWidth, mode.m_nHeight, ImageLoader::GetName( mode.m_Format ) );
  1626. Warning("Vertex Shader Version : %d.%d Pixel Shader Version : %d.%d\n",
  1627. (caps.VertexShaderVersion >> 8) & 0xFF, caps.VertexShaderVersion & 0xFF,
  1628. (caps.PixelShaderVersion >> 8) & 0xFF, caps.PixelShaderVersion & 0xFF);
  1629. Warning("\nDevice Caps :\n");
  1630. Warning("CANBLTSYSTONONLOCAL %s CANRENDERAFTERFLIP %s HWRASTERIZATION %s\n",
  1631. (caps.DevCaps & D3DDEVCAPS_CANBLTSYSTONONLOCAL) ? " Y " : " N ",
  1632. (caps.DevCaps & D3DDEVCAPS_CANRENDERAFTERFLIP) ? " Y " : " N ",
  1633. (caps.DevCaps & D3DDEVCAPS_HWRASTERIZATION) ? " Y " : "*N*" );
  1634. Warning("HWTRANSFORMANDLIGHT %s NPATCHES %s PUREDEVICE %s\n",
  1635. (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? " Y " : " N ",
  1636. (caps.DevCaps & D3DDEVCAPS_NPATCHES) ? " Y " : " N ",
  1637. (caps.DevCaps & D3DDEVCAPS_PUREDEVICE) ? " Y " : " N " );
  1638. Warning("SEPARATETEXTUREMEMORIES %s TEXTURENONLOCALVIDMEM %s TEXTURESYSTEMMEMORY %s\n",
  1639. (caps.DevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES) ? "*Y*" : " N ",
  1640. (caps.DevCaps & D3DDEVCAPS_TEXTURENONLOCALVIDMEM) ? " Y " : " N ",
  1641. (caps.DevCaps & D3DDEVCAPS_TEXTURESYSTEMMEMORY) ? " Y " : " N " );
  1642. Warning("TEXTUREVIDEOMEMORY %s TLVERTEXSYSTEMMEMORY %s TLVERTEXVIDEOMEMORY %s\n",
  1643. (caps.DevCaps & D3DDEVCAPS_TEXTUREVIDEOMEMORY) ? " Y " : "*N*",
  1644. (caps.DevCaps & D3DDEVCAPS_TLVERTEXSYSTEMMEMORY) ? " Y " : "*N*",
  1645. (caps.DevCaps & D3DDEVCAPS_TLVERTEXVIDEOMEMORY) ? " Y " : " N " );
  1646. Warning("\nPrimitive Caps :\n");
  1647. Warning("BLENDOP %s CLIPPLANESCALEDPOINTS %s CLIPTLVERTS %s\n",
  1648. (caps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) ? " Y " : " N ",
  1649. (caps.PrimitiveMiscCaps & D3DPMISCCAPS_CLIPPLANESCALEDPOINTS) ? " Y " : " N ",
  1650. (caps.PrimitiveMiscCaps & D3DPMISCCAPS_CLIPTLVERTS) ? " Y " : " N " );
  1651. Warning("COLORWRITEENABLE %s MASKZ %s TSSARGTEMP %s\n",
  1652. (caps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) ? " Y " : " N ",
  1653. (caps.PrimitiveMiscCaps & D3DPMISCCAPS_MASKZ) ? " Y " : "*N*",
  1654. (caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) ? " Y " : " N " );
  1655. Warning("\nRaster Caps :\n");
  1656. Warning("FOGRANGE %s FOGTABLE %s FOGVERTEX %s ZFOG %s WFOG %s\n",
  1657. (caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? " Y " : " N ",
  1658. (caps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) ? " Y " : " N ",
  1659. (caps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX) ? " Y " : " N ",
  1660. (caps.RasterCaps & D3DPRASTERCAPS_ZFOG) ? " Y " : " N ",
  1661. (caps.RasterCaps & D3DPRASTERCAPS_WFOG) ? " Y " : " N " );
  1662. Warning("MIPMAPLODBIAS %s WBUFFER %s ZBIAS %s ZTEST %s\n",
  1663. (caps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) ? " Y " : " N ",
  1664. (caps.RasterCaps & D3DPRASTERCAPS_WBUFFER) ? " Y " : " N ",
  1665. (caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) ? " Y " : " N ",
  1666. (caps.RasterCaps & D3DPRASTERCAPS_ZTEST) ? " Y " : "*N*" );
  1667. Warning("Size of Texture Memory : %d kb\n", g_pHardwareConfig->Caps().m_TextureMemorySize / 1024 );
  1668. Warning("Max Texture Dimensions : %d x %d\n",
  1669. caps.MaxTextureWidth, caps.MaxTextureHeight );
  1670. if (caps.MaxTextureAspectRatio != 0)
  1671. Warning("Max Texture Aspect Ratio : *%d*\n", caps.MaxTextureAspectRatio );
  1672. Warning("Max Textures : %d Max Stages : %d\n",
  1673. caps.MaxSimultaneousTextures, caps.MaxTextureBlendStages );
  1674. Warning("\nTexture Caps :\n");
  1675. Warning("ALPHA %s CUBEMAP %s MIPCUBEMAP %s SQUAREONLY %s\n",
  1676. (caps.TextureCaps & D3DPTEXTURECAPS_ALPHA) ? " Y " : " N ",
  1677. (caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) ? " Y " : " N ",
  1678. (caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP) ? " Y " : " N ",
  1679. (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) ? "*Y*" : " N " );
  1680. Warning( "vendor id: 0x%x\n", g_pHardwareConfig->ActualCaps().m_VendorID );
  1681. Warning( "device id: 0x%x\n", g_pHardwareConfig->ActualCaps().m_DeviceID );
  1682. Warning( "SHADERAPI CAPS:\n" );
  1683. Warning( "m_NumSamplers: %d\n", g_pHardwareConfig->Caps().m_NumSamplers );
  1684. Warning( "m_NumTextureStages: %d\n", g_pHardwareConfig->Caps().m_NumTextureStages );
  1685. Warning( "m_HasSetDeviceGammaRamp: %s\n", g_pHardwareConfig->Caps().m_HasSetDeviceGammaRamp ? "yes" : "no" );
  1686. Warning( "m_SupportsVertexShaders (1.1): %s\n", g_pHardwareConfig->Caps().m_SupportsVertexShaders ? "yes" : "no" );
  1687. Warning( "m_SupportsVertexShaders_2_0: %s\n", g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 ? "yes" : "no" );
  1688. Warning( "m_SupportsPixelShaders (1.1): %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders ? "yes" : "no" );
  1689. Warning( "m_SupportsPixelShaders_1_4: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_1_4 ? "yes" : "no" );
  1690. Warning( "m_SupportsPixelShaders_2_0: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_2_0 ? "yes" : "no" );
  1691. Warning( "m_SupportsPixelShaders_2_b: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_2_b ? "yes" : "no" );
  1692. Warning( "m_SupportsShaderModel_3_0: %s\n", g_pHardwareConfig->Caps().m_SupportsShaderModel_3_0 ? "yes" : "no" );
  1693. switch( g_pHardwareConfig->Caps().m_SupportsCompressedTextures )
  1694. {
  1695. case COMPRESSED_TEXTURES_ON:
  1696. Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_ON\n" );
  1697. break;
  1698. case COMPRESSED_TEXTURES_OFF:
  1699. Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_ON\n" );
  1700. break;
  1701. case COMPRESSED_TEXTURES_NOT_INITIALIZED:
  1702. Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_NOT_INITIALIZED\n" );
  1703. break;
  1704. default:
  1705. Assert( 0 );
  1706. break;
  1707. }
  1708. Warning( "m_SupportsCompressedVertices: %d\n", g_pHardwareConfig->Caps().m_SupportsCompressedVertices );
  1709. Warning( "m_bSupportsAnisotropicFiltering: %s\n", g_pHardwareConfig->Caps().m_bSupportsAnisotropicFiltering ? "yes" : "no" );
  1710. Warning( "m_nMaxAnisotropy: %d\n", g_pHardwareConfig->Caps().m_nMaxAnisotropy );
  1711. Warning( "m_MaxTextureWidth: %d\n", g_pHardwareConfig->Caps().m_MaxTextureWidth );
  1712. Warning( "m_MaxTextureHeight: %d\n", g_pHardwareConfig->Caps().m_MaxTextureHeight );
  1713. Warning( "m_MaxTextureAspectRatio: %d\n", g_pHardwareConfig->Caps().m_MaxTextureAspectRatio );
  1714. Warning( "m_MaxPrimitiveCount: %d\n", g_pHardwareConfig->Caps().m_MaxPrimitiveCount );
  1715. Warning( "m_ZBiasAndSlopeScaledDepthBiasSupported: %s\n", g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported ? "yes" : "no" );
  1716. Warning( "m_SupportsMipmapping: %s\n", g_pHardwareConfig->Caps().m_SupportsMipmapping ? "yes" : "no" );
  1717. Warning( "m_SupportsOverbright: %s\n", g_pHardwareConfig->Caps().m_SupportsOverbright ? "yes" : "no" );
  1718. Warning( "m_SupportsCubeMaps: %s\n", g_pHardwareConfig->Caps().m_SupportsCubeMaps ? "yes" : "no" );
  1719. Warning( "m_NumPixelShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumPixelShaderConstants );
  1720. Warning( "m_NumVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumVertexShaderConstants );
  1721. Warning( "m_NumBooleanVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants );
  1722. Warning( "m_NumIntegerVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants );
  1723. Warning( "m_TextureMemorySize: %d\n", g_pHardwareConfig->Caps().m_TextureMemorySize );
  1724. Warning( "m_MaxNumLights: %d\n", g_pHardwareConfig->Caps().m_MaxNumLights );
  1725. Warning( "m_SupportsHardwareLighting: %s\n", g_pHardwareConfig->Caps().m_SupportsHardwareLighting ? "yes" : "no" );
  1726. Warning( "m_MaxBlendMatrices: %d\n", g_pHardwareConfig->Caps().m_MaxBlendMatrices );
  1727. Warning( "m_MaxBlendMatrixIndices: %d\n", g_pHardwareConfig->Caps().m_MaxBlendMatrixIndices );
  1728. Warning( "m_MaxVertexShaderBlendMatrices: %d\n", g_pHardwareConfig->Caps().m_MaxVertexShaderBlendMatrices );
  1729. Warning( "m_SupportsMipmappedCubemaps: %s\n", g_pHardwareConfig->Caps().m_SupportsMipmappedCubemaps ? "yes" : "no" );
  1730. Warning( "m_SupportsNonPow2Textures: %s\n", g_pHardwareConfig->Caps().m_SupportsNonPow2Textures ? "yes" : "no" );
  1731. Warning( "m_nDXSupportLevel: %d\n", g_pHardwareConfig->Caps().m_nDXSupportLevel );
  1732. Warning( "m_PreferDynamicTextures: %s\n", g_pHardwareConfig->Caps().m_PreferDynamicTextures ? "yes" : "no" );
  1733. Warning( "m_HasProjectedBumpEnv: %s\n", g_pHardwareConfig->Caps().m_HasProjectedBumpEnv ? "yes" : "no" );
  1734. Warning( "m_MaxUserClipPlanes: %d\n", g_pHardwareConfig->Caps().m_MaxUserClipPlanes );
  1735. Warning( "m_SupportsSRGB: %s\n", g_pHardwareConfig->Caps().m_SupportsSRGB ? "yes" : "no" );
  1736. switch( g_pHardwareConfig->Caps().m_HDRType )
  1737. {
  1738. case HDR_TYPE_NONE:
  1739. Warning( "m_HDRType: HDR_TYPE_NONE\n" );
  1740. break;
  1741. case HDR_TYPE_INTEGER:
  1742. Warning( "m_HDRType: HDR_TYPE_INTEGER\n" );
  1743. break;
  1744. case HDR_TYPE_FLOAT:
  1745. Warning( "m_HDRType: HDR_TYPE_FLOAT\n" );
  1746. break;
  1747. default:
  1748. Assert( 0 );
  1749. break;
  1750. }
  1751. Warning( "m_bSupportsSpheremapping: %s\n", g_pHardwareConfig->Caps().m_bSupportsSpheremapping ? "yes" : "no" );
  1752. Warning( "m_UseFastClipping: %s\n", g_pHardwareConfig->Caps().m_UseFastClipping ? "yes" : "no" );
  1753. Warning( "m_pShaderDLL: %s\n", g_pHardwareConfig->Caps().m_pShaderDLL );
  1754. Warning( "m_bNeedsATICentroidHack: %s\n", g_pHardwareConfig->Caps().m_bNeedsATICentroidHack ? "yes" : "no" );
  1755. Warning( "m_bDisableShaderOptimizations: %s\n", g_pHardwareConfig->Caps().m_bDisableShaderOptimizations ? "yes" : "no" );
  1756. Warning( "m_bColorOnSecondStream: %s\n", g_pHardwareConfig->Caps().m_bColorOnSecondStream ? "yes" : "no" );
  1757. Warning( "m_MaxSimultaneousRenderTargets: %d\n", g_pHardwareConfig->Caps().m_MaxSimultaneousRenderTargets );
  1758. }
  1759. //-----------------------------------------------------------------------------
  1760. // Back buffer information
  1761. //-----------------------------------------------------------------------------
  1762. ImageFormat CShaderDeviceDx8::GetBackBufferFormat() const
  1763. {
  1764. return ImageLoader::D3DFormatToImageFormat( m_PresentParameters.BackBufferFormat );
  1765. }
  1766. void CShaderDeviceDx8::GetBackBufferDimensions( int& width, int& height ) const
  1767. {
  1768. width = m_PresentParameters.BackBufferWidth;
  1769. height = m_PresentParameters.BackBufferHeight;
  1770. }
  1771. //-----------------------------------------------------------------------------
  1772. // Detects support for CreateQuery
  1773. //-----------------------------------------------------------------------------
  1774. void CShaderDeviceDx8::DetectQuerySupport( IDirect3DDevice9 *pD3DDevice )
  1775. {
  1776. // Do I need to detect whether this device supports CreateQuery before creating it?
  1777. if ( m_DeviceSupportsCreateQuery != -1 )
  1778. return;
  1779. IDirect3DQuery9 *pQueryObject = NULL;
  1780. // Detect whether query is supported by creating and releasing:
  1781. HRESULT hr = pD3DDevice->CreateQuery( D3DQUERYTYPE_EVENT, &pQueryObject );
  1782. if ( !FAILED(hr) && pQueryObject )
  1783. {
  1784. pQueryObject->Release();
  1785. m_DeviceSupportsCreateQuery = 1;
  1786. }
  1787. else
  1788. {
  1789. m_DeviceSupportsCreateQuery = 0;
  1790. }
  1791. }
  1792. const char *GetD3DErrorText( HRESULT hr )
  1793. {
  1794. const char *pszMoreInfo = NULL;
  1795. #if defined( _WIN32 ) && !defined(DX_TO_GL_ABSTRACTION)
  1796. switch ( hr )
  1797. {
  1798. case D3DERR_WRONGTEXTUREFORMAT:
  1799. pszMoreInfo = "D3DERR_WRONGTEXTUREFORMAT: The pixel format of the texture surface is not valid.";
  1800. break;
  1801. case D3DERR_UNSUPPORTEDCOLOROPERATION:
  1802. pszMoreInfo = "D3DERR_UNSUPPORTEDCOLOROPERATION: The device does not support a specified texture-blending operation for color values.";
  1803. break;
  1804. case D3DERR_UNSUPPORTEDCOLORARG:
  1805. pszMoreInfo = "D3DERR_UNSUPPORTEDCOLORARG: The device does not support a specified texture-blending argument for color values.";
  1806. break;
  1807. case D3DERR_UNSUPPORTEDALPHAOPERATION:
  1808. pszMoreInfo = "D3DERR_UNSUPPORTEDALPHAOPERATION: The device does not support a specified texture-blending operation for the alpha channel.";
  1809. break;
  1810. case D3DERR_UNSUPPORTEDALPHAARG:
  1811. pszMoreInfo = "D3DERR_UNSUPPORTEDALPHAARG: The device does not support a specified texture-blending argument for the alpha channel.";
  1812. break;
  1813. case D3DERR_TOOMANYOPERATIONS:
  1814. pszMoreInfo = "D3DERR_TOOMANYOPERATIONS: The application is requesting more texture-filtering operations than the device supports.";
  1815. break;
  1816. case D3DERR_CONFLICTINGTEXTUREFILTER:
  1817. pszMoreInfo = "D3DERR_CONFLICTINGTEXTUREFILTER: The current texture filters cannot be used together.";
  1818. break;
  1819. case D3DERR_UNSUPPORTEDFACTORVALUE:
  1820. pszMoreInfo = "D3DERR_UNSUPPORTEDFACTORVALUE: The device does not support the specified texture factor value.";
  1821. break;
  1822. case D3DERR_CONFLICTINGRENDERSTATE:
  1823. pszMoreInfo = "D3DERR_CONFLICTINGRENDERSTATE: The currently set render states cannot be used together.";
  1824. break;
  1825. case D3DERR_UNSUPPORTEDTEXTUREFILTER:
  1826. pszMoreInfo = "D3DERR_UNSUPPORTEDTEXTUREFILTER: The device does not support the specified texture filter.";
  1827. break;
  1828. case D3DERR_CONFLICTINGTEXTUREPALETTE:
  1829. pszMoreInfo = "D3DERR_CONFLICTINGTEXTUREPALETTE: The current textures cannot be used simultaneously.";
  1830. break;
  1831. case D3DERR_DRIVERINTERNALERROR:
  1832. pszMoreInfo = "D3DERR_DRIVERINTERNALERROR: Internal driver error.";
  1833. break;
  1834. case D3DERR_NOTFOUND:
  1835. pszMoreInfo = "D3DERR_NOTFOUND: The requested item was not found.";
  1836. break;
  1837. case D3DERR_DEVICELOST:
  1838. pszMoreInfo = "D3DERR_DEVICELOST: The device has been lost but cannot be reset at this time. Therefore, rendering is not possible.";
  1839. break;
  1840. case D3DERR_DEVICENOTRESET:
  1841. pszMoreInfo = "D3DERR_DEVICENOTRESET: The device has been lost.";
  1842. break;
  1843. case D3DERR_NOTAVAILABLE:
  1844. pszMoreInfo = "D3DERR_NOTAVAILABLE: This device does not support the queried technique.";
  1845. break;
  1846. case D3DERR_OUTOFVIDEOMEMORY:
  1847. pszMoreInfo = "D3DERR_OUTOFVIDEOMEMORY: Direct3D does not have enough display memory to perform the operation. The device is using more resources in a single scene than can fit simultaneously into video memory.";
  1848. break;
  1849. case D3DERR_INVALIDDEVICE:
  1850. pszMoreInfo = "D3DERR_INVALIDDEVICE: The requested device type is not valid.";
  1851. break;
  1852. case D3DERR_INVALIDCALL:
  1853. pszMoreInfo = "D3DERR_INVALIDCALL: The method call is invalid.";
  1854. break;
  1855. case D3DERR_DRIVERINVALIDCALL:
  1856. pszMoreInfo = "D3DERR_DRIVERINVALIDCALL";
  1857. break;
  1858. case D3DERR_WASSTILLDRAWING:
  1859. pszMoreInfo = "D3DERR_WASSTILLDRAWING: The previous blit operation that is transferring information to or from this surface is incomplete.";
  1860. break;
  1861. }
  1862. #endif // _WIN32
  1863. return pszMoreInfo;
  1864. }
  1865. //-----------------------------------------------------------------------------
  1866. // Actually creates the D3D Device once the present parameters are set up
  1867. //-----------------------------------------------------------------------------
  1868. IDirect3DDevice9* CShaderDeviceDx8::InvokeCreateDevice( void* hWnd, int nAdapter, DWORD deviceCreationFlags )
  1869. {
  1870. IDirect3DDevice9 *pD3DDevice = NULL;
  1871. D3DDEVTYPE devType = DX8_DEVTYPE;
  1872. #if NVPERFHUD
  1873. nAdapter = D3D()->GetAdapterCount()-1;
  1874. devType = D3DDEVTYPE_REF;
  1875. deviceCreationFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1876. #endif
  1877. #if 1 // with the changes for opengl to enable threading, we no longer need the d3d device to have threading guards
  1878. #ifndef _X360
  1879. // Create the device with multi-threaded safeguards if we're using mat_queue_mode 2.
  1880. // The logic to enable multithreaded rendering happens well after the device has been created,
  1881. // so we replicate some of that logic here.
  1882. ConVarRef mat_queue_mode( "mat_queue_mode" );
  1883. if ( mat_queue_mode.GetInt() == 2 ||
  1884. ( mat_queue_mode.GetInt() == -2 && GetCPUInformation()->m_nPhysicalProcessors >= 2 ) ||
  1885. ( mat_queue_mode.GetInt() == -1 && GetCPUInformation()->m_nPhysicalProcessors >= 2 ) )
  1886. {
  1887. deviceCreationFlags |= D3DCREATE_MULTITHREADED;
  1888. }
  1889. #endif
  1890. #endif
  1891. #ifdef ENABLE_NULLREF_DEVICE_SUPPORT
  1892. devType = CommandLine()->FindParm( "-nulldevice" ) ? D3DDEVTYPE_NULLREF: devType;
  1893. #endif
  1894. HRESULT hr = D3D()->CreateDevice( nAdapter, devType,
  1895. (VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
  1896. if ( !FAILED( hr ) && pD3DDevice )
  1897. return pD3DDevice;
  1898. if ( !IsPC() )
  1899. return NULL;
  1900. // try again, other applications may be taking their time
  1901. Sleep( 1000 );
  1902. hr = D3D()->CreateDevice( nAdapter, devType,
  1903. (VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
  1904. if ( !FAILED( hr ) && pD3DDevice )
  1905. return pD3DDevice;
  1906. // in this case, we actually are allocating too much memory....
  1907. // This will cause us to use less buffers...
  1908. if ( m_PresentParameters.Windowed )
  1909. {
  1910. m_PresentParameters.SwapEffect = D3DSWAPEFFECT_COPY;
  1911. m_PresentParameters.BackBufferCount = 0;
  1912. hr = D3D()->CreateDevice( nAdapter, devType,
  1913. (VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
  1914. }
  1915. if ( !FAILED( hr ) && pD3DDevice )
  1916. return pD3DDevice;
  1917. const char *pszMoreInfo = NULL;
  1918. switch ( hr )
  1919. {
  1920. #ifdef _WIN32
  1921. case D3DERR_INVALIDCALL:
  1922. // Override the error text for this error since it has a known meaning for CreateDevice failures.
  1923. pszMoreInfo = "D3DERR_INVALIDCALL: The device or the device driver may not support Direct3D or may not support the resolution or color depth specified.";
  1924. break;
  1925. #endif // _WIN32
  1926. default:
  1927. pszMoreInfo = GetD3DErrorText( hr );
  1928. break;
  1929. }
  1930. // Otherwise we failed, show a message and shutdown
  1931. if ( pszMoreInfo )
  1932. {
  1933. DWarning( "init", 0, "Failed to create %s device!\nError 0x%lX: %s\n\nPlease see the following for more info.\n"
  1934. "http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=772\n", IsOpenGL() ? "OpenGL" : "D3D", hr, pszMoreInfo );
  1935. }
  1936. else
  1937. {
  1938. DWarning( "init", 0, "Failed to create %s device!\nError 0x%lX.\n\nPlease see the following for more info.\n"
  1939. "http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=772\n", IsOpenGL() ? "OpenGL" : "D3D", hr );
  1940. }
  1941. return NULL;
  1942. }
  1943. //-----------------------------------------------------------------------------
  1944. // Creates the D3D Device
  1945. //-----------------------------------------------------------------------------
  1946. bool CShaderDeviceDx8::CreateD3DDevice( void* pHWnd, int nAdapter, const ShaderDeviceInfo_t &info )
  1947. {
  1948. Assert( info.m_nVersion == SHADER_DEVICE_INFO_VERSION );
  1949. MEM_ALLOC_CREDIT_( __FILE__ ": D3D Device" );
  1950. VD3DHWND hWnd = (VD3DHWND)pHWnd;
  1951. #if ( !defined( PIX_INSTRUMENTATION ) && !defined( _X360 ) && !defined( NVPERFHUD ) )
  1952. D3DPERF_SetOptions(1); // Explicitly disallow PIX instrumented profiling in external builds
  1953. #endif
  1954. // Get some caps....
  1955. D3DCAPS caps;
  1956. HRESULT hr = D3D()->GetDeviceCaps( nAdapter, DX8_DEVTYPE, &caps );
  1957. if ( FAILED( hr ) )
  1958. return false;
  1959. // Determine the adapter format
  1960. ShaderDisplayMode_t mode;
  1961. g_pShaderDeviceMgrDx8->GetCurrentModeInfo( &mode, nAdapter );
  1962. m_AdapterFormat = mode.m_Format;
  1963. // FIXME: Need to do this prior to SetPresentParameters. Fix.
  1964. // Make it part of HardwareCaps_t
  1965. InitializeColorInformation( nAdapter, DX8_DEVTYPE, m_AdapterFormat );
  1966. const HardwareCaps_t &adapterCaps = g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter );
  1967. DWORD deviceCreationFlags = ComputeDeviceCreationFlags( caps, adapterCaps.m_bSoftwareVertexProcessing );
  1968. SetPresentParameters( hWnd, nAdapter, info );
  1969. // Tell all other instances of the material system to let go of memory
  1970. SendIPCMessage( RELEASE_MESSAGE );
  1971. // Creates the device
  1972. IDirect3DDevice9 *pD3DDevice = InvokeCreateDevice( pHWnd, nAdapter, deviceCreationFlags );
  1973. if ( !pD3DDevice )
  1974. return false;
  1975. // Check to see if query is supported
  1976. DetectQuerySupport( pD3DDevice );
  1977. #ifdef STUBD3D
  1978. Dx9Device() = new CStubD3DDevice( pD3DDevice, g_pFullFileSystem );
  1979. #else
  1980. g_pD3DDevice = pD3DDevice;
  1981. #endif
  1982. #if defined( _X360 )
  1983. // Create the depth buffer, created manually to enable hierarchical z
  1984. {
  1985. D3DSURFACE_PARAMETERS DepthStencilParams;
  1986. // Depth is immediately after the back buffer in EDRAM
  1987. // allocate the hierarchical z tiles at the end of the area so all other allocations can trivially allocate at 0
  1988. DepthStencilParams.Base = XGSurfaceSize(
  1989. m_PresentParameters.BackBufferWidth,
  1990. m_PresentParameters.BackBufferHeight,
  1991. m_PresentParameters.BackBufferFormat,
  1992. m_PresentParameters.MultiSampleType );
  1993. DepthStencilParams.ColorExpBias = 0;
  1994. DepthStencilParams.HierarchicalZBase = GPU_HIERARCHICAL_Z_TILES - XGHierarchicalZSize( m_PresentParameters.BackBufferWidth, m_PresentParameters.BackBufferHeight, m_PresentParameters.MultiSampleType );
  1995. IDirect3DSurface *pDepthStencilSurface = NULL;
  1996. hr = Dx9Device()->CreateDepthStencilSurface(
  1997. m_PresentParameters.BackBufferWidth,
  1998. m_PresentParameters.BackBufferHeight,
  1999. m_PresentParameters.AutoDepthStencilFormat,
  2000. m_PresentParameters.MultiSampleType,
  2001. m_PresentParameters.MultiSampleQuality,
  2002. TRUE,
  2003. &pDepthStencilSurface,
  2004. &DepthStencilParams );
  2005. Assert( SUCCEEDED( hr ) );
  2006. if ( FAILED( hr ) )
  2007. return false;
  2008. hr = Dx9Device()->SetDepthStencilSurface( pDepthStencilSurface );
  2009. Assert( SUCCEEDED( hr ) );
  2010. if ( FAILED( hr ) )
  2011. return false;
  2012. }
  2013. // Initialize XUI, needed for TTF font rasterization
  2014. // xui requires and shares our d3d device
  2015. {
  2016. hr = XuiRenderInitShared( pD3DDevice, &m_PresentParameters, XuiD3DXTextureLoader );
  2017. if ( FAILED( hr ) )
  2018. return false;
  2019. XUIInitParams xuiInit;
  2020. XUI_INIT_PARAMS( xuiInit );
  2021. xuiInit.dwFlags = XUI_INIT_PARAMS_FLAGS_NONE;
  2022. xuiInit.pHooks = NULL;
  2023. hr = XuiInit( &xuiInit );
  2024. if ( FAILED( hr ) )
  2025. return false;
  2026. hr = XuiRenderCreateDC( &m_hDC );
  2027. if ( FAILED( hr ) )
  2028. return false;
  2029. }
  2030. #endif
  2031. // CheckDeviceLost();
  2032. // Tell all other instances of the material system it's ok to grab memory
  2033. SendIPCMessage( REACQUIRE_MESSAGE );
  2034. m_hWnd = pHWnd;
  2035. m_nAdapter = m_DisplayAdapter = nAdapter;
  2036. m_DeviceState = DEVICE_STATE_OK;
  2037. m_bIsMinimized = false;
  2038. m_bQueuedDeviceLost = false;
  2039. m_IsResizing = info.m_bWindowed && info.m_bResizing;
  2040. // This is our current view.
  2041. m_ViewHWnd = hWnd;
  2042. GetWindowSize( m_nWindowWidth, m_nWindowHeight );
  2043. g_pHardwareConfig->SetupHardwareCaps( info, g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter ) );
  2044. // FIXME: Bake this into hardware config
  2045. // What texture formats do we support?
  2046. if ( D3DSupportsCompressedTextures() )
  2047. {
  2048. g_pHardwareConfig->ActualCapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
  2049. g_pHardwareConfig->CapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
  2050. }
  2051. else
  2052. {
  2053. g_pHardwareConfig->ActualCapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
  2054. g_pHardwareConfig->CapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
  2055. }
  2056. return ( !FAILED( hr ) );
  2057. }
  2058. //-----------------------------------------------------------------------------
  2059. // Frame sync
  2060. //-----------------------------------------------------------------------------
  2061. void CShaderDeviceDx8::AllocFrameSyncTextureObject()
  2062. {
  2063. if ( IsX360() )
  2064. return;
  2065. FreeFrameSyncTextureObject();
  2066. // Create a tiny managed texture.
  2067. HRESULT hr = Dx9Device()->CreateTexture(
  2068. 1, 1, // width, height
  2069. 0, // levels
  2070. D3DUSAGE_DYNAMIC, // usage
  2071. D3DFMT_A8R8G8B8, // format
  2072. D3DPOOL_DEFAULT,
  2073. &m_pFrameSyncTexture,
  2074. NULL );
  2075. if ( FAILED( hr ) )
  2076. {
  2077. m_pFrameSyncTexture = NULL;
  2078. }
  2079. }
  2080. void CShaderDeviceDx8::FreeFrameSyncTextureObject()
  2081. {
  2082. if ( IsX360() )
  2083. return;
  2084. if ( m_pFrameSyncTexture )
  2085. {
  2086. m_pFrameSyncTexture->Release();
  2087. m_pFrameSyncTexture = NULL;
  2088. }
  2089. }
  2090. void CShaderDeviceDx8::AllocFrameSyncObjects( void )
  2091. {
  2092. if ( IsX360() )
  2093. return;
  2094. if ( mat_debugalttab.GetBool() )
  2095. {
  2096. Warning( "mat_debugalttab: CShaderAPIDX8::AllocFrameSyncObjects\n" );
  2097. }
  2098. // Allocate the texture for frame syncing in case we force that to be on.
  2099. AllocFrameSyncTextureObject();
  2100. if ( m_DeviceSupportsCreateQuery == 0 )
  2101. {
  2102. for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
  2103. {
  2104. m_pFrameSyncQueryObject[i] = NULL;
  2105. m_bQueryIssued[i] = false;
  2106. }
  2107. return;
  2108. }
  2109. // FIXME FIXME FIXME!!!!! Need to record this.
  2110. for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
  2111. {
  2112. HRESULT hr = Dx9Device()->CreateQuery( D3DQUERYTYPE_EVENT, &m_pFrameSyncQueryObject[i] );
  2113. if( hr == D3DERR_NOTAVAILABLE )
  2114. {
  2115. Warning( "D3DQUERYTYPE_EVENT not available on this driver\n" );
  2116. Assert( m_pFrameSyncQueryObject[i] == NULL );
  2117. }
  2118. else
  2119. {
  2120. Assert( hr == D3D_OK );
  2121. Assert( m_pFrameSyncQueryObject[i] );
  2122. m_pFrameSyncQueryObject[i]->Issue( D3DISSUE_END );
  2123. m_bQueryIssued[i] = true;
  2124. }
  2125. }
  2126. }
  2127. void CShaderDeviceDx8::FreeFrameSyncObjects( void )
  2128. {
  2129. if ( IsX360() )
  2130. return;
  2131. if ( mat_debugalttab.GetBool() )
  2132. {
  2133. Warning( "mat_debugalttab: CShaderAPIDX8::FreeFrameSyncObjects\n" );
  2134. }
  2135. FreeFrameSyncTextureObject();
  2136. // FIXME FIXME FIXME!!!!! Need to record this.
  2137. for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
  2138. {
  2139. if ( m_pFrameSyncQueryObject[i] )
  2140. {
  2141. if ( m_bQueryIssued[i] )
  2142. {
  2143. tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "D3DQueryGetData %t", tmSendCallStack( TELEMETRY_LEVEL0, 0 ) );
  2144. double flStartTime = Plat_FloatTime();
  2145. BOOL dummyData = 0;
  2146. HRESULT hr = S_OK;
  2147. // Make every attempt (within 2 seconds) to get the result from the query. Doing so may prevent
  2148. // crashes in the driver if we try to release outstanding queries.
  2149. do
  2150. {
  2151. hr = m_pFrameSyncQueryObject[i]->GetData( &dummyData, sizeof( dummyData ), D3DGETDATA_FLUSH );
  2152. double flCurrTime = Plat_FloatTime();
  2153. // don't wait more than 2 seconds for these
  2154. if ( flCurrTime - flStartTime > 2.00 )
  2155. break;
  2156. } while ( hr == S_FALSE );
  2157. }
  2158. #ifdef DBGFLAG_ASSERT
  2159. int nRetVal =
  2160. #endif
  2161. m_pFrameSyncQueryObject[i]->Release();
  2162. Assert( nRetVal == 0 );
  2163. m_pFrameSyncQueryObject[i] = NULL;
  2164. m_bQueryIssued[i] = false;
  2165. }
  2166. }
  2167. }
  2168. //-----------------------------------------------------------------------------
  2169. // Occurs when another application is initializing
  2170. //-----------------------------------------------------------------------------
  2171. void CShaderDeviceDx8::OtherAppInitializing( bool initializing )
  2172. {
  2173. if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
  2174. {
  2175. if ( initializing )
  2176. {
  2177. ShaderUtil()->OnThreadEvent( SHADER_THREAD_OTHER_APP_START );
  2178. }
  2179. else
  2180. {
  2181. ShaderUtil()->OnThreadEvent( SHADER_THREAD_OTHER_APP_END );
  2182. }
  2183. return;
  2184. }
  2185. Assert( m_bOtherAppInitializing != initializing );
  2186. if ( !IsDeactivated() )
  2187. {
  2188. Dx9Device()->EndScene();
  2189. }
  2190. // NOTE: OtherApp is set in this way because we need to know we're
  2191. // active as we release and restore everything
  2192. CheckDeviceLost( initializing );
  2193. if ( !IsDeactivated() )
  2194. {
  2195. Dx9Device()->BeginScene();
  2196. }
  2197. }
  2198. void CShaderDeviceDx8::HandleThreadEvent( uint32 threadEvent )
  2199. {
  2200. Assert(ThreadOwnsDevice());
  2201. switch ( threadEvent )
  2202. {
  2203. case SHADER_THREAD_OTHER_APP_START:
  2204. OtherAppInitializing(true);
  2205. break;
  2206. case SHADER_THREAD_RELEASE_RESOURCES:
  2207. ReleaseResources();
  2208. break;
  2209. case SHADER_THREAD_EVICT_RESOURCES:
  2210. EvictManagedResourcesInternal();
  2211. break;
  2212. case SHADER_THREAD_RESET_RENDER_STATE:
  2213. ResetRenderState();
  2214. break;
  2215. case SHADER_THREAD_ACQUIRE_RESOURCES:
  2216. ReacquireResources();
  2217. break;
  2218. case SHADER_THREAD_OTHER_APP_END:
  2219. OtherAppInitializing(false);
  2220. break;
  2221. }
  2222. }
  2223. //-----------------------------------------------------------------------------
  2224. // We lost the device, but we have a chance to recover
  2225. //-----------------------------------------------------------------------------
  2226. bool CShaderDeviceDx8::TryDeviceReset()
  2227. {
  2228. if ( IsX360() )
  2229. return true;
  2230. // Don't try to reset the device until we're sure our resources have been released
  2231. if ( !m_bResourcesReleased )
  2232. {
  2233. return false;
  2234. }
  2235. // FIXME: Make this rebuild the Dx9Device from scratch!
  2236. // Helps with compatibility
  2237. HRESULT hr = Dx9Device()->Reset( &m_PresentParameters );
  2238. bool bResetSuccess = !FAILED(hr);
  2239. #if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
  2240. if ( bResetSuccess && g_ShaderDeviceUsingD3D9Ex )
  2241. {
  2242. bResetSuccess = SUCCEEDED( Dx9Device()->TestCooperativeLevel() );
  2243. if ( bResetSuccess )
  2244. {
  2245. Warning("video driver has crashed and been reset, re-uploading resources now");
  2246. }
  2247. }
  2248. #endif
  2249. if ( bResetSuccess )
  2250. m_bResourcesReleased = false;
  2251. return bResetSuccess;
  2252. }
  2253. //-----------------------------------------------------------------------------
  2254. // Release, reacquire resources
  2255. //-----------------------------------------------------------------------------
  2256. void CShaderDeviceDx8::ReleaseResources()
  2257. {
  2258. if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
  2259. {
  2260. // Set our resources as not being released yet.
  2261. // We reset this in two places since release resources can be called without a call to TryDeviceReset.
  2262. m_bResourcesReleased = false;
  2263. ShaderUtil()->OnThreadEvent( SHADER_THREAD_RELEASE_RESOURCES );
  2264. return;
  2265. }
  2266. // Only the initial "ReleaseResources" actually has effect
  2267. if ( m_numReleaseResourcesRefCount ++ != 0 )
  2268. {
  2269. Warning( "ReleaseResources has no effect, now at level %d.\n", m_numReleaseResourcesRefCount );
  2270. DevWarning( "ReleaseResources called twice is a bug: use IsDeactivated to check for a valid device.\n" );
  2271. Assert( 0 );
  2272. return;
  2273. }
  2274. LOCK_SHADERAPI();
  2275. CPixEvent( PIX_VALVE_ORANGE, "ReleaseResources" );
  2276. FreeFrameSyncObjects();
  2277. FreeNonInteractiveRefreshObjects();
  2278. ShaderUtil()->ReleaseShaderObjects();
  2279. MeshMgr()->ReleaseBuffers();
  2280. g_pShaderAPI->ReleaseShaderObjects();
  2281. #ifdef _DEBUG
  2282. if ( MeshMgr()->BufferCount() != 0 )
  2283. {
  2284. for( int i = 0; i < MeshMgr()->BufferCount(); i++ )
  2285. {
  2286. }
  2287. }
  2288. #endif
  2289. // All meshes cleaned up?
  2290. Assert( MeshMgr()->BufferCount() == 0 );
  2291. // Signal that our resources have been released so that we can try to reset the device
  2292. m_bResourcesReleased = true;
  2293. }
  2294. void CShaderDeviceDx8::ReacquireResources()
  2295. {
  2296. ReacquireResourcesInternal();
  2297. }
  2298. void CShaderDeviceDx8::ReacquireResourcesInternal( bool bResetState, bool bForceReacquire, char const *pszForceReason )
  2299. {
  2300. if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
  2301. {
  2302. if ( bResetState )
  2303. {
  2304. ShaderUtil()->OnThreadEvent( SHADER_THREAD_RESET_RENDER_STATE );
  2305. }
  2306. ShaderUtil()->OnThreadEvent( SHADER_THREAD_ACQUIRE_RESOURCES );
  2307. return;
  2308. }
  2309. if ( bForceReacquire )
  2310. {
  2311. // If we are forcing reacquire then warn if release calls are remaining unpaired
  2312. if ( m_numReleaseResourcesRefCount > 1 )
  2313. {
  2314. Warning( "Forcefully resetting device (%s), resources release level was %d.\n", pszForceReason ? pszForceReason : "unspecified", m_numReleaseResourcesRefCount );
  2315. Assert( 0 );
  2316. }
  2317. m_numReleaseResourcesRefCount = 0;
  2318. }
  2319. else
  2320. {
  2321. // Only the final "ReacquireResources" actually has effect
  2322. if ( -- m_numReleaseResourcesRefCount != 0 )
  2323. {
  2324. Warning( "ReacquireResources has no effect, now at level %d.\n", m_numReleaseResourcesRefCount );
  2325. DevWarning( "ReacquireResources being discarded is a bug: use IsDeactivated to check for a valid device.\n" );
  2326. Assert( 0 );
  2327. if ( m_numReleaseResourcesRefCount < 0 )
  2328. {
  2329. m_numReleaseResourcesRefCount = 0;
  2330. }
  2331. return;
  2332. }
  2333. }
  2334. if ( bResetState )
  2335. {
  2336. ResetRenderState();
  2337. }
  2338. LOCK_SHADERAPI();
  2339. CPixEvent event( PIX_VALVE_ORANGE, "ReacquireResources" );
  2340. g_pShaderAPI->RestoreShaderObjects();
  2341. AllocFrameSyncObjects();
  2342. AllocNonInteractiveRefreshObjects();
  2343. MeshMgr()->RestoreBuffers();
  2344. ShaderUtil()->RestoreShaderObjects( CShaderDeviceMgrBase::ShaderInterfaceFactory );
  2345. }
  2346. //-----------------------------------------------------------------------------
  2347. // Changes the window size
  2348. //-----------------------------------------------------------------------------
  2349. bool CShaderDeviceDx8::ResizeWindow( const ShaderDeviceInfo_t &info )
  2350. {
  2351. if ( IsX360() )
  2352. return false;
  2353. m_bPendingVideoModeChange = false;
  2354. // We don't need to do crap if the window was set up to set up
  2355. // to be resizing...
  2356. if ( info.m_bResizing )
  2357. return false;
  2358. g_pShaderDeviceMgr->InvokeModeChangeCallbacks();
  2359. ReleaseResources();
  2360. SetPresentParameters( (VD3DHWND)m_hWnd, m_DisplayAdapter, info );
  2361. HRESULT hr = Dx9Device()->Reset( &m_PresentParameters );
  2362. if ( FAILED( hr ) )
  2363. {
  2364. Warning( "ResizeWindow: Reset failed, hr = 0x%08lX.\n", hr );
  2365. return false;
  2366. }
  2367. else
  2368. {
  2369. ReacquireResourcesInternal( true, true, "ResizeWindow" );
  2370. }
  2371. return true;
  2372. }
  2373. //-----------------------------------------------------------------------------
  2374. // Queue up the fact that the device was lost
  2375. //-----------------------------------------------------------------------------
  2376. void CShaderDeviceDx8::MarkDeviceLost( )
  2377. {
  2378. if ( IsX360() )
  2379. return;
  2380. m_bQueuedDeviceLost = true;
  2381. }
  2382. //-----------------------------------------------------------------------------
  2383. // Checks if the device was lost
  2384. //-----------------------------------------------------------------------------
  2385. #if defined( _DEBUG ) && !defined( _X360 )
  2386. ConVar mat_forcelostdevice( "mat_forcelostdevice", "0" );
  2387. #endif
  2388. void CShaderDeviceDx8::CheckDeviceLost( bool bOtherAppInitializing )
  2389. {
  2390. #if !defined( _X360 )
  2391. // FIXME: We could also queue up if WM_SIZE changes and look at that
  2392. // but that seems to only make sense if we have resizable windows where
  2393. // we do *not* allocate buffers as large as the entire current video mode
  2394. // which we're not doing
  2395. #ifdef _WIN32
  2396. m_bIsMinimized = ( static_cast<BOOL>(IsIconic( ( HWND )m_hWnd )) == (BOOL)TRUE );
  2397. #else
  2398. m_bIsMinimized = ( IsIconic( (VD3DHWND)m_hWnd ) == TRUE );
  2399. #endif
  2400. m_bOtherAppInitializing = bOtherAppInitializing;
  2401. #ifdef _DEBUG
  2402. if ( mat_forcelostdevice.GetBool() )
  2403. {
  2404. mat_forcelostdevice.SetValue( 0 );
  2405. MarkDeviceLost();
  2406. }
  2407. #endif
  2408. HRESULT hr = D3D_OK;
  2409. #if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
  2410. if ( g_ShaderDeviceUsingD3D9Ex && m_DeviceState == DEVICE_STATE_OK )
  2411. {
  2412. // Steady state - PresentEx return value will mark us lost if necessary.
  2413. // We do not care if we are minimized in this state.
  2414. m_bIsMinimized = false;
  2415. }
  2416. else
  2417. #endif
  2418. {
  2419. RECORD_COMMAND( DX8_TEST_COOPERATIVE_LEVEL, 0 );
  2420. hr = Dx9Device()->TestCooperativeLevel();
  2421. }
  2422. // If some other call returned device lost previously in the frame, spoof the return value from TCL
  2423. if ( m_bQueuedDeviceLost )
  2424. {
  2425. hr = (hr != D3D_OK) ? hr : D3DERR_DEVICENOTRESET;
  2426. m_bQueuedDeviceLost = false;
  2427. }
  2428. if ( m_DeviceState == DEVICE_STATE_OK )
  2429. {
  2430. // We can transition out of ok if bOtherAppInitializing is set
  2431. // or if we become minimized, or if TCL returns anything other than D3D_OK.
  2432. if ( ( hr != D3D_OK ) || m_bIsMinimized )
  2433. {
  2434. // purge unreferenced materials
  2435. g_pShaderUtil->UncacheUnusedMaterials( true );
  2436. // We were ok, now we're not. Release resources
  2437. ReleaseResources();
  2438. m_DeviceState = DEVICE_STATE_LOST_DEVICE;
  2439. }
  2440. else if ( bOtherAppInitializing )
  2441. {
  2442. // purge unreferenced materials
  2443. g_pShaderUtil->UncacheUnusedMaterials( true );
  2444. // We were ok, now we're not. Release resources
  2445. ReleaseResources();
  2446. m_DeviceState = DEVICE_STATE_OTHER_APP_INIT;
  2447. }
  2448. }
  2449. // Immediately checking devicelost after ok helps in the case where we got D3DERR_DEVICENOTRESET
  2450. // in which case we want to immdiately try to switch out of DEVICE_STATE_LOST and into DEVICE_STATE_NEEDS_RESET
  2451. if ( m_DeviceState == DEVICE_STATE_LOST_DEVICE )
  2452. {
  2453. // We can only try to reset if we're not minimized and not lost
  2454. if ( !m_bIsMinimized && (hr != D3DERR_DEVICELOST) )
  2455. {
  2456. m_DeviceState = DEVICE_STATE_NEEDS_RESET;
  2457. }
  2458. }
  2459. // Immediately checking needs reset also helps for the case where we got D3DERR_DEVICENOTRESET
  2460. if ( m_DeviceState == DEVICE_STATE_NEEDS_RESET )
  2461. {
  2462. if ( ( hr == D3DERR_DEVICELOST ) || m_bIsMinimized )
  2463. {
  2464. m_DeviceState = DEVICE_STATE_LOST_DEVICE;
  2465. }
  2466. else
  2467. {
  2468. bool bResetSucceeded = TryDeviceReset();
  2469. if ( bResetSucceeded )
  2470. {
  2471. if ( !bOtherAppInitializing )
  2472. {
  2473. m_DeviceState = DEVICE_STATE_OK;
  2474. // We were bad, now we're ok. Restore resources and reset render state.
  2475. ReacquireResourcesInternal( true, true, "NeedsReset" );
  2476. }
  2477. else
  2478. {
  2479. m_DeviceState = DEVICE_STATE_OTHER_APP_INIT;
  2480. }
  2481. }
  2482. }
  2483. }
  2484. if ( m_DeviceState == DEVICE_STATE_OTHER_APP_INIT )
  2485. {
  2486. if ( ( hr != D3D_OK ) || m_bIsMinimized )
  2487. {
  2488. m_DeviceState = DEVICE_STATE_LOST_DEVICE;
  2489. }
  2490. else if ( !bOtherAppInitializing )
  2491. {
  2492. m_DeviceState = DEVICE_STATE_OK;
  2493. // We were bad, now we're ok. Restore resources and reset render state.
  2494. ReacquireResourcesInternal( true, true, "OtherAppInit" );
  2495. }
  2496. }
  2497. // Do mode change if we have a video mode change.
  2498. if ( m_bPendingVideoModeChange && !IsDeactivated() )
  2499. {
  2500. #ifdef _DEBUG
  2501. Warning( "mode change!\n" );
  2502. #endif
  2503. // now purge unreferenced materials
  2504. g_pShaderUtil->UncacheUnusedMaterials( true );
  2505. ResizeWindow( m_PendingVideoModeChangeConfig );
  2506. }
  2507. #endif
  2508. }
  2509. //-----------------------------------------------------------------------------
  2510. // Special method to refresh the screen on the XBox360
  2511. //-----------------------------------------------------------------------------
  2512. bool CShaderDeviceDx8::AllocNonInteractiveRefreshObjects()
  2513. {
  2514. #if defined( _X360 )
  2515. const char *strVertexShaderProgram =
  2516. " float4x4 matWVP : register(c0);"
  2517. " struct VS_IN"
  2518. " {"
  2519. " float4 ObjPos : POSITION;"
  2520. " float2 TexCoord : TEXCOORD;"
  2521. " };"
  2522. " struct VS_OUT"
  2523. " {"
  2524. " float4 ProjPos : POSITION;"
  2525. " float2 TexCoord : TEXCOORD;"
  2526. " };"
  2527. " VS_OUT main( VS_IN In )"
  2528. " {"
  2529. " VS_OUT Out; "
  2530. " Out.ProjPos = mul( matWVP, In.ObjPos );"
  2531. " Out.TexCoord = In.TexCoord;"
  2532. " return Out;"
  2533. " }";
  2534. const char *strPixelShaderProgram =
  2535. " struct PS_IN"
  2536. " {"
  2537. " float2 TexCoord : TEXCOORD;"
  2538. " };"
  2539. " sampler detail : register( s0 );"
  2540. " float4 main( PS_IN In ) : COLOR"
  2541. " {"
  2542. " return tex2D( detail, In.TexCoord );"
  2543. " }";
  2544. const char *strPixelShaderProgram2 =
  2545. " struct PS_IN"
  2546. " {"
  2547. " float2 TexCoord : TEXCOORD;"
  2548. " };"
  2549. " sampler detail : register( s0 );"
  2550. " float4 main( PS_IN In ) : COLOR"
  2551. " {"
  2552. " return tex2D( detail, In.TexCoord );"
  2553. " }";
  2554. const char *strPixelShaderProgram3 =
  2555. " struct PS_IN"
  2556. " {"
  2557. " float2 TexCoord : TEXCOORD;"
  2558. " };"
  2559. " float SrgbGammaToLinear( float flSrgbGammaValue )"
  2560. " {"
  2561. " float x = saturate( flSrgbGammaValue );"
  2562. " return ( x <= 0.04045f ) ? ( x / 12.92f ) : ( pow( ( x + 0.055f ) / 1.055f, 2.4f ) );"
  2563. " }"
  2564. "float X360LinearToGamma( float flLinearValue )"
  2565. "{"
  2566. " float fl360GammaValue;"
  2567. ""
  2568. " flLinearValue = saturate( flLinearValue );"
  2569. " if ( flLinearValue < ( 128.0f / 1023.0f ) )"
  2570. " {"
  2571. " if ( flLinearValue < ( 64.0f / 1023.0f ) )"
  2572. " {"
  2573. " fl360GammaValue = flLinearValue * ( 1023.0f * ( 1.0f / 255.0f ) );"
  2574. " }"
  2575. " else"
  2576. " {"
  2577. " fl360GammaValue = flLinearValue * ( ( 1023.0f / 2.0f ) * ( 1.0f / 255.0f ) ) + ( 32.0f / 255.0f );"
  2578. " }"
  2579. " }"
  2580. " else"
  2581. " {"
  2582. " if ( flLinearValue < ( 512.0f / 1023.0f ) )"
  2583. " {"
  2584. " fl360GammaValue = flLinearValue * ( ( 1023.0f / 4.0f ) * ( 1.0f / 255.0f ) ) + ( 64.0f / 255.0f );"
  2585. " }"
  2586. " else"
  2587. " {"
  2588. " fl360GammaValue = flLinearValue * ( ( 1023.0f /8.0f ) * ( 1.0f / 255.0f ) ) + ( 128.0f /255.0f );"
  2589. " if ( fl360GammaValue > 1.0f )"
  2590. " {"
  2591. " fl360GammaValue = 1.0f;"
  2592. " }"
  2593. " }"
  2594. " }"
  2595. ""
  2596. " fl360GammaValue = saturate( fl360GammaValue );"
  2597. " return fl360GammaValue;"
  2598. "}"
  2599. " sampler detail : register( s0 );"
  2600. " float4 main( PS_IN In ) : COLOR"
  2601. " {"
  2602. " float4 vTextureColor = tex2D( detail, In.TexCoord );"
  2603. " vTextureColor.r = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.r ) );"
  2604. " vTextureColor.g = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.g ) );"
  2605. " vTextureColor.b = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.b ) );"
  2606. " return vTextureColor;"
  2607. " }";
  2608. D3DVERTEXELEMENT9 VertexElements[4] =
  2609. {
  2610. { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  2611. { 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
  2612. D3DDECL_END()
  2613. };
  2614. ID3DXBuffer *pErrorMsg = NULL;
  2615. ID3DXBuffer *pShaderCode = NULL;
  2616. HRESULT hr = D3DXCompileShader( strVertexShaderProgram, (UINT)strlen( strVertexShaderProgram ), NULL, NULL, "main", "vs_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
  2617. if ( FAILED( hr ) )
  2618. return false;
  2619. Dx9Device()->CreateVertexShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pVertexShader );
  2620. pShaderCode->Release();
  2621. pShaderCode = NULL;
  2622. if ( pErrorMsg )
  2623. {
  2624. pErrorMsg->Release();
  2625. pErrorMsg = NULL;
  2626. }
  2627. hr = D3DXCompileShader( strPixelShaderProgram, (UINT)strlen( strPixelShaderProgram ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
  2628. if ( FAILED(hr) )
  2629. return false;
  2630. Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShader );
  2631. pShaderCode->Release();
  2632. if ( pErrorMsg )
  2633. {
  2634. pErrorMsg->Release();
  2635. pErrorMsg = NULL;
  2636. }
  2637. hr = D3DXCompileShader( strPixelShaderProgram3, (UINT)strlen( strPixelShaderProgram3 ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
  2638. if ( FAILED(hr) )
  2639. return false;
  2640. Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShaderStartup );
  2641. pShaderCode->Release();
  2642. if ( pErrorMsg )
  2643. {
  2644. pErrorMsg->Release();
  2645. pErrorMsg = NULL;
  2646. }
  2647. hr = D3DXCompileShader( strPixelShaderProgram2, (UINT)strlen( strPixelShaderProgram2 ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
  2648. if ( FAILED(hr) )
  2649. return false;
  2650. Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 );
  2651. pShaderCode->Release();
  2652. if ( pErrorMsg )
  2653. {
  2654. pErrorMsg->Release();
  2655. pErrorMsg = NULL;
  2656. }
  2657. // Create a vertex declaration from the element descriptions.
  2658. Dx9Device()->CreateVertexDeclaration( VertexElements, &m_NonInteractiveRefresh.m_pVertexDecl );
  2659. #endif
  2660. return true;
  2661. }
  2662. void CShaderDeviceDx8::FreeNonInteractiveRefreshObjects()
  2663. {
  2664. if ( m_NonInteractiveRefresh.m_pVertexShader )
  2665. {
  2666. m_NonInteractiveRefresh.m_pVertexShader->Release();
  2667. m_NonInteractiveRefresh.m_pVertexShader = NULL;
  2668. }
  2669. if ( m_NonInteractiveRefresh.m_pPixelShader )
  2670. {
  2671. m_NonInteractiveRefresh.m_pPixelShader->Release();
  2672. m_NonInteractiveRefresh.m_pPixelShader = NULL;
  2673. }
  2674. if ( m_NonInteractiveRefresh.m_pPixelShaderStartup )
  2675. {
  2676. m_NonInteractiveRefresh.m_pPixelShaderStartup->Release();
  2677. m_NonInteractiveRefresh.m_pPixelShaderStartup = NULL;
  2678. }
  2679. if ( m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 )
  2680. {
  2681. m_NonInteractiveRefresh.m_pPixelShaderStartupPass2->Release();
  2682. m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 = NULL;
  2683. }
  2684. if ( m_NonInteractiveRefresh.m_pVertexDecl )
  2685. {
  2686. m_NonInteractiveRefresh.m_pVertexDecl->Release();
  2687. m_NonInteractiveRefresh.m_pVertexDecl = NULL;
  2688. }
  2689. }
  2690. bool CShaderDeviceDx8::InNonInteractiveMode() const
  2691. {
  2692. return m_NonInteractiveRefresh.m_Mode != MATERIAL_NON_INTERACTIVE_MODE_NONE;
  2693. }
  2694. void CShaderDeviceDx8::EnableNonInteractiveMode( MaterialNonInteractiveMode_t mode, ShaderNonInteractiveInfo_t *pInfo )
  2695. {
  2696. if ( !IsX360() )
  2697. return;
  2698. if ( pInfo && ( pInfo->m_hTempFullscreenTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) )
  2699. {
  2700. mode = MATERIAL_NON_INTERACTIVE_MODE_NONE;
  2701. }
  2702. m_NonInteractiveRefresh.m_Mode = mode;
  2703. if ( pInfo )
  2704. {
  2705. m_NonInteractiveRefresh.m_Info = *pInfo;
  2706. }
  2707. m_NonInteractiveRefresh.m_nPacifierFrame = 0;
  2708. if ( mode != MATERIAL_NON_INTERACTIVE_MODE_NONE )
  2709. {
  2710. ConVarRef mat_monitorgamma( "mat_monitorgamma" );
  2711. ConVarRef mat_monitorgamma_tv_range_min( "mat_monitorgamma_tv_range_min" );
  2712. ConVarRef mat_monitorgamma_tv_range_max( "mat_monitorgamma_tv_range_max" );
  2713. ConVarRef mat_monitorgamma_tv_exp( "mat_monitorgamma_tv_exp" );
  2714. ConVarRef mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled" );
  2715. SetHardwareGammaRamp( mat_monitorgamma.GetFloat(), mat_monitorgamma_tv_range_min.GetFloat(), mat_monitorgamma_tv_range_max.GetFloat(),
  2716. mat_monitorgamma_tv_exp.GetFloat(), mat_monitorgamma_tv_enabled.GetBool() );
  2717. }
  2718. #ifdef _X360
  2719. if ( mode != MATERIAL_NON_INTERACTIVE_MODE_NONE )
  2720. {
  2721. // HACK: VSync off (prevents us wasting time blocking on VSync due to our irregular present intervals)
  2722. Dx9Device()->SetRenderState( D3DRS_PRESENTINTERVAL, D3DPRESENT_INTERVAL_IMMEDIATE );
  2723. }
  2724. else
  2725. {
  2726. // HACK: VSync on (defaulting to on on 360 is fine, but really should save+restore this state)
  2727. Dx9Device()->SetRenderState( D3DRS_PRESENTINTERVAL, D3DPRESENT_INTERVAL_ONE );
  2728. }
  2729. #endif
  2730. // Msg( "Time elapsed: %.3f Peak %.3f Ave %.5f Count %d Count Above %d\n", Plat_FloatTime() - m_NonInteractiveRefresh.m_flStartTime,
  2731. // m_NonInteractiveRefresh.m_flPeakDt, m_NonInteractiveRefresh.m_flTotalDt / m_NonInteractiveRefresh.m_nSamples, m_NonInteractiveRefresh.m_nSamples, m_NonInteractiveRefresh.m_nCountAbove66 );
  2732. m_NonInteractiveRefresh.m_flStartTime = m_NonInteractiveRefresh.m_flLastPresentTime =
  2733. m_NonInteractiveRefresh.m_flLastPacifierTime = Plat_FloatTime();
  2734. m_NonInteractiveRefresh.m_flPeakDt = 0.0f;
  2735. m_NonInteractiveRefresh.m_flTotalDt = 0.0f;
  2736. m_NonInteractiveRefresh.m_nSamples = 0;
  2737. m_NonInteractiveRefresh.m_nCountAbove66 = 0;
  2738. }
  2739. void CShaderDeviceDx8::UpdatePresentStats()
  2740. {
  2741. float t = Plat_FloatTime();
  2742. float flActualDt = t - m_NonInteractiveRefresh.m_flLastPresentTime;
  2743. if ( flActualDt > m_NonInteractiveRefresh.m_flPeakDt )
  2744. {
  2745. m_NonInteractiveRefresh.m_flPeakDt = flActualDt;
  2746. }
  2747. if ( flActualDt > 0.066 )
  2748. {
  2749. ++m_NonInteractiveRefresh.m_nCountAbove66;
  2750. }
  2751. m_NonInteractiveRefresh.m_flTotalDt += flActualDt;
  2752. ++m_NonInteractiveRefresh.m_nSamples;
  2753. t = Plat_FloatTime();
  2754. m_NonInteractiveRefresh.m_flLastPresentTime = t;
  2755. }
  2756. void CShaderDeviceDx8::RefreshFrontBufferNonInteractive()
  2757. {
  2758. if ( !IsX360() || !InNonInteractiveMode() )
  2759. return;
  2760. // Other code should not be talking to D3D at the same time as this
  2761. AUTO_LOCK( m_nonInteractiveModeMutex );
  2762. #ifdef _X360
  2763. g_pShaderAPI->OwnGPUResources( false );
  2764. IDirect3DBaseTexture *pTexture = g_pShaderAPI->GetD3DTexture( m_NonInteractiveRefresh.m_Info.m_hTempFullscreenTexture );
  2765. int w, h;
  2766. g_pShaderAPI->GetBackBufferDimensions( w, h );
  2767. XMMATRIX matWVP = XMMatrixOrthographicOffCenterLH( 0, (FLOAT)w, (FLOAT)h, 0, 0, 1 );
  2768. // Structure to hold vertex data.
  2769. struct TEXVERTEX
  2770. {
  2771. FLOAT Position[3];
  2772. FLOAT TexCoord[2];
  2773. };
  2774. TEXVERTEX Vertices[4];
  2775. Vertices[0].Position[0] = -0.5f;
  2776. Vertices[0].Position[1] = -0.5f;
  2777. Vertices[0].Position[2] = 0;
  2778. Vertices[0].TexCoord[0] = 0;
  2779. Vertices[0].TexCoord[1] = 0;
  2780. Vertices[1].Position[0] = w-0.5f;
  2781. Vertices[1].Position[1] = -0.5f;
  2782. Vertices[1].Position[2] = 0;
  2783. Vertices[1].TexCoord[0] = 1;
  2784. Vertices[1].TexCoord[1] = 0;
  2785. Vertices[2].Position[0] = w-0.5f;
  2786. Vertices[2].Position[1] = h-0.5f;
  2787. Vertices[2].Position[2] = 0;
  2788. Vertices[2].TexCoord[0] = 1;
  2789. Vertices[2].TexCoord[1] = 1;
  2790. Vertices[3].Position[0] = -0.5f;
  2791. Vertices[3].Position[1] = h-0.5f;
  2792. Vertices[3].Position[2] = 0;
  2793. Vertices[3].TexCoord[0] = 0;
  2794. Vertices[3].TexCoord[1] = 1;
  2795. D3DVIEWPORT9 viewport;
  2796. viewport.X = viewport.Y = 0;
  2797. viewport.Width = w; viewport.Height = h;
  2798. viewport.MinZ = ReverseDepthOnX360() ? 1.0f : 0.0f;
  2799. viewport.MaxZ = 1.0f - viewport.MinZ;
  2800. bool bInStartupMode = ( m_NonInteractiveRefresh.m_Mode == MATERIAL_NON_INTERACTIVE_MODE_STARTUP );
  2801. float flDepth = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? 0.0f : 1.0f;
  2802. Dx9Device()->Clear( 0, NULL, D3DCLEAR_ZBUFFER, 0, flDepth, 0L );
  2803. Dx9Device()->SetViewport( &viewport );
  2804. Dx9Device()->SetTexture( 0, pTexture );
  2805. Dx9Device()->SetVertexShader( m_NonInteractiveRefresh.m_pVertexShader );
  2806. Dx9Device()->SetPixelShader( bInStartupMode ? m_NonInteractiveRefresh.m_pPixelShaderStartup : m_NonInteractiveRefresh.m_pPixelShader );
  2807. Dx9Device()->SetVertexShaderConstantF( 0, (FLOAT*)&matWVP, 4 );
  2808. Dx9Device()->SetVertexDeclaration( m_NonInteractiveRefresh.m_pVertexDecl );
  2809. Dx9Device()->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
  2810. Dx9Device()->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
  2811. Dx9Device()->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  2812. Dx9Device()->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  2813. tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
  2814. Dx9Device()->DrawPrimitiveUP( D3DPT_QUADLIST, 1, Vertices, sizeof( TEXVERTEX ) );
  2815. if ( bInStartupMode )
  2816. {
  2817. float flXPos = m_NonInteractiveRefresh.m_Info.m_flNormalizedX;
  2818. float flYPos = m_NonInteractiveRefresh.m_Info.m_flNormalizedY;
  2819. float flHeight = m_NonInteractiveRefresh.m_Info.m_flNormalizedSize;
  2820. int nSize = h * flHeight;
  2821. int x = w * flXPos - nSize * 0.5f;
  2822. int y = h * flYPos - nSize * 0.5f;
  2823. w = h = nSize;
  2824. Vertices[0].Position[0] = x - 0.5f;
  2825. Vertices[0].Position[1] = y - 0.5f;
  2826. Vertices[1].Position[0] = x+w-0.5f;
  2827. Vertices[1].Position[1] = y - 0.5f;
  2828. Vertices[2].Position[0] = x+w-0.5f;
  2829. Vertices[2].Position[1] = y+h-0.5f;
  2830. Vertices[3].Position[0] = x - 0.5f;
  2831. Vertices[3].Position[1] = y+h-0.5f;
  2832. float t = Plat_FloatTime();
  2833. float flDt = t - m_NonInteractiveRefresh.m_flLastPacifierTime;
  2834. if ( flDt > 0.030f )
  2835. {
  2836. if ( ++m_NonInteractiveRefresh.m_nPacifierFrame >= m_NonInteractiveRefresh.m_Info.m_nPacifierCount )
  2837. {
  2838. m_NonInteractiveRefresh.m_nPacifierFrame = 0;
  2839. }
  2840. m_NonInteractiveRefresh.m_flLastPacifierTime = t;
  2841. }
  2842. pTexture = g_pShaderAPI->GetD3DTexture( m_NonInteractiveRefresh.m_Info.m_pPacifierTextures[ m_NonInteractiveRefresh.m_nPacifierFrame ] );
  2843. Dx9Device()->SetRenderState( D3DRS_ALPHABLENDENABLE, 1 );
  2844. Dx9Device()->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  2845. Dx9Device()->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  2846. Dx9Device()->SetTexture( 0, pTexture );
  2847. Dx9Device()->SetPixelShader( m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 );
  2848. Dx9Device()->DrawPrimitiveUP( D3DPT_QUADLIST, 1, Vertices, sizeof( TEXVERTEX ) );
  2849. }
  2850. Dx9Device()->SetVertexShader( NULL );
  2851. Dx9Device()->SetPixelShader( NULL );
  2852. Dx9Device()->SetTexture( 0, NULL );
  2853. Dx9Device()->SetVertexDeclaration( NULL );
  2854. tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "D3DPresent" );
  2855. Dx9Device()->Present( 0, 0, 0, 0 );
  2856. g_pShaderAPI->QueueResetRenderState();
  2857. g_pShaderAPI->OwnGPUResources( true );
  2858. UpdatePresentStats();
  2859. #endif
  2860. }
  2861. //-----------------------------------------------------------------------------
  2862. // Page flip
  2863. //-----------------------------------------------------------------------------
  2864. void CShaderDeviceDx8::Present()
  2865. {
  2866. LOCK_SHADERAPI();
  2867. // need to flush the dynamic buffer
  2868. g_pShaderAPI->FlushBufferedPrimitives();
  2869. if ( !IsDeactivated() )
  2870. {
  2871. Dx9Device()->EndScene();
  2872. }
  2873. HRESULT hr = S_OK;
  2874. // if we're in queued mode, don't present if the device is already lost
  2875. bool bValidPresent = true;
  2876. bool bInMainThread = ThreadInMainThread();
  2877. if ( !bInMainThread )
  2878. {
  2879. // don't present if the device is in an invalid state and in queued mode
  2880. if ( m_DeviceState != DEVICE_STATE_OK )
  2881. {
  2882. bValidPresent = false;
  2883. }
  2884. // check for lost device early in threaded mode
  2885. CheckDeviceLost( m_bOtherAppInitializing );
  2886. if ( m_DeviceState != DEVICE_STATE_OK )
  2887. {
  2888. bValidPresent = false;
  2889. }
  2890. }
  2891. // Copy the back buffer into the non-interactive temp buffer
  2892. if ( m_NonInteractiveRefresh.m_Mode == MATERIAL_NON_INTERACTIVE_MODE_LEVEL_LOAD )
  2893. {
  2894. g_pShaderAPI->CopyRenderTargetToTextureEx( m_NonInteractiveRefresh.m_Info.m_hTempFullscreenTexture, 0, NULL, NULL );
  2895. }
  2896. // If we're not iconified, try to present (without this check, we can flicker when Alt-Tabbed away)
  2897. #ifdef _WIN32
  2898. if ( IsX360() || (IsIconic( ( HWND )m_hWnd ) == 0 && bValidPresent) )
  2899. #else
  2900. if ( IsX360() || (IsIconic( (VD3DHWND)m_hWnd ) == 0 && bValidPresent) )
  2901. #endif
  2902. {
  2903. if ( IsPC() && ( m_IsResizing || ( m_ViewHWnd != (VD3DHWND)m_hWnd ) ) )
  2904. {
  2905. RECT destRect;
  2906. #ifndef DX_TO_GL_ABSTRACTION
  2907. GetClientRect( ( HWND )m_ViewHWnd, &destRect );
  2908. #else
  2909. toglGetClientRect( (VD3DHWND)m_ViewHWnd, &destRect );
  2910. #endif
  2911. ShaderViewport_t viewport;
  2912. g_pShaderAPI->GetViewports( &viewport, 1 );
  2913. RECT srcRect;
  2914. srcRect.left = viewport.m_nTopLeftX;
  2915. srcRect.right = viewport.m_nTopLeftX + viewport.m_nWidth;
  2916. srcRect.top = viewport.m_nTopLeftY;
  2917. srcRect.bottom = viewport.m_nTopLeftY + viewport.m_nHeight;
  2918. hr = Dx9Device()->Present( &srcRect, &destRect, (VD3DHWND)m_ViewHWnd, 0 );
  2919. }
  2920. else
  2921. {
  2922. g_pShaderAPI->OwnGPUResources( false );
  2923. hr = Dx9Device()->Present( 0, 0, 0, 0 );
  2924. }
  2925. }
  2926. UpdatePresentStats();
  2927. if ( IsWindows() )
  2928. {
  2929. if ( hr == D3DERR_DRIVERINTERNALERROR )
  2930. {
  2931. /* Usually this bug means that the driver has run out of internal video
  2932. memory, due to leaking it slowly over several application restarts.
  2933. As of summer 2007, IE in particular seemed to leak a lot of driver
  2934. memory for every image context it created in the browser window. A
  2935. reboot clears out the leaked memory and will generally allow the game
  2936. to be run again; occasionally (but not frequently) it's necessary to
  2937. reduce video settings in the game as well to run. But, this is too
  2938. fine a distinction to explain in a dialog, so place the guilt on the
  2939. user and ask them to reduce video settings regardless.
  2940. */
  2941. Error( "Internal driver error at Present.\n"
  2942. "You're likely out of OS Paged Pool Memory! For more info, see\n"
  2943. "http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
  2944. }
  2945. if ( hr == D3DERR_DEVICELOST )
  2946. {
  2947. MarkDeviceLost();
  2948. }
  2949. }
  2950. MeshMgr()->DiscardVertexBuffers();
  2951. if ( bInMainThread )
  2952. {
  2953. CheckDeviceLost( m_bOtherAppInitializing );
  2954. }
  2955. if ( IsX360() )
  2956. {
  2957. // according to docs - "Mandatory Reset of GPU Registers"
  2958. // 360 must force the cached state to be dirty after any present()
  2959. g_pShaderAPI->ResetRenderState( false );
  2960. }
  2961. #ifdef RECORD_KEYFRAMES
  2962. static int frame = 0;
  2963. ++frame;
  2964. if (frame == KEYFRAME_INTERVAL)
  2965. {
  2966. RECORD_COMMAND( DX8_KEYFRAME, 0 );
  2967. g_pShaderAPI->ResetRenderState();
  2968. frame = 0;
  2969. }
  2970. #endif
  2971. g_pShaderAPI->AdvancePIXFrame();
  2972. if ( !IsDeactivated() )
  2973. {
  2974. #ifndef DX_TO_GL_ABSTRACTION
  2975. if ( ( ShaderUtil()->GetConfig().bMeasureFillRate || ShaderUtil()->GetConfig().bVisualizeFillRate ) )
  2976. {
  2977. g_pShaderAPI->ClearBuffers( true, true, true, -1, -1 );
  2978. }
  2979. #endif
  2980. Dx9Device()->BeginScene();
  2981. }
  2982. }
  2983. // We need to scale our colors to the range [16, 235] to keep our colors within TV standards. Some colors might
  2984. // still be out of gamut if any of the R, G, or B channels are more than 191 units apart from each other in
  2985. // the 0-255 scale, but it looks like the 360 deals with this for us by lowering the bright saturated color components.
  2986. // NOTE: I'm leaving the max at 255 to retain whiter than whites. On most TV's, we seems a little dark in the bright colors
  2987. // compared to TV and movies when played in the same conditions. This keeps out brights on par with what customers are
  2988. // used to seeing.
  2989. // TV's generally have a 2.5 gamma, so we need to convert our 2.2 frame buffer into a 2.5 frame buffer for display on a TV
  2990. void CShaderDeviceDx8::SetHardwareGammaRamp( float fGamma, float fGammaTVRangeMin, float fGammaTVRangeMax, float fGammaTVExponent, bool bTVEnabled )
  2991. {
  2992. DevMsg( 2, "SetHardwareGammaRamp( %f )\n", fGamma );
  2993. Assert( Dx9Device() );
  2994. if( !Dx9Device() )
  2995. return;
  2996. D3DGAMMARAMP gammaRamp;
  2997. for ( int i = 0; i < 256; i++ )
  2998. {
  2999. float flInputValue = float( i ) / 255.0f;
  3000. // Since the 360's sRGB read/write is a piecewise linear approximation, we need to correct for the difference in gamma space here
  3001. float flSrgbGammaValue;
  3002. if ( IsX360() ) // Should we also do this for the PS3?
  3003. {
  3004. // First undo the 360 broken sRGB curve by bringing the value back into linear space
  3005. float flLinearValue = X360GammaToLinear( flInputValue );
  3006. flLinearValue = clamp( flLinearValue, 0.0f, 1.0f );
  3007. // Now apply a true sRGB curve to mimic PC hardware
  3008. flSrgbGammaValue = SrgbLinearToGamma( flLinearValue ); // ( flLinearValue <= 0.0031308f ) ? ( flLinearValue * 12.92f ) : ( 1.055f * powf( flLinearValue, ( 1.0f / 2.4f ) ) ) - 0.055f;
  3009. flSrgbGammaValue = clamp( flSrgbGammaValue, 0.0f, 1.0f );
  3010. }
  3011. else
  3012. {
  3013. flSrgbGammaValue = flInputValue;
  3014. }
  3015. // Apply the user controlled exponent curve
  3016. float flCorrection = pow( flSrgbGammaValue, ( fGamma / 2.2f ) );
  3017. flCorrection = clamp( flCorrection, 0.0f, 1.0f );
  3018. // TV adjustment - Apply an exp and a scale and bias
  3019. if ( bTVEnabled )
  3020. {
  3021. // Adjust for TV gamma of 2.5 by applying an exponent of 2.2 / 2.5 = 0.88
  3022. flCorrection = pow( flCorrection, 2.2f / fGammaTVExponent );
  3023. flCorrection = clamp( flCorrection, 0.0f, 1.0f );
  3024. // Scale and bias to fit into the 16-235 range for TV's
  3025. flCorrection = ( flCorrection * ( fGammaTVRangeMax - fGammaTVRangeMin ) / 255.0f ) + ( fGammaTVRangeMin / 255.0f );
  3026. flCorrection = clamp( flCorrection, 0.0f, 1.0f );
  3027. }
  3028. // Generate final int value
  3029. unsigned int val = ( int )( flCorrection * 65535.0f );
  3030. gammaRamp.red[i] = val;
  3031. gammaRamp.green[i] = val;
  3032. gammaRamp.blue[i] = val;
  3033. }
  3034. Dx9Device()->SetGammaRamp( 0, D3DSGR_NO_CALIBRATION, &gammaRamp );
  3035. }
  3036. //-----------------------------------------------------------------------------
  3037. // Shader compilation
  3038. //-----------------------------------------------------------------------------
  3039. IShaderBuffer* CShaderDeviceDx8::CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion )
  3040. {
  3041. return ShaderManager()->CompileShader( pProgram, nBufLen, pShaderVersion );
  3042. }
  3043. VertexShaderHandle_t CShaderDeviceDx8::CreateVertexShader( IShaderBuffer *pBuffer )
  3044. {
  3045. return ShaderManager()->CreateVertexShader( pBuffer );
  3046. }
  3047. void CShaderDeviceDx8::DestroyVertexShader( VertexShaderHandle_t hShader )
  3048. {
  3049. ShaderManager()->DestroyVertexShader( hShader );
  3050. }
  3051. GeometryShaderHandle_t CShaderDeviceDx8::CreateGeometryShader( IShaderBuffer* pShaderBuffer )
  3052. {
  3053. Assert( 0 );
  3054. return GEOMETRY_SHADER_HANDLE_INVALID;
  3055. }
  3056. void CShaderDeviceDx8::DestroyGeometryShader( GeometryShaderHandle_t hShader )
  3057. {
  3058. Assert( hShader == GEOMETRY_SHADER_HANDLE_INVALID );
  3059. }
  3060. PixelShaderHandle_t CShaderDeviceDx8::CreatePixelShader( IShaderBuffer *pBuffer )
  3061. {
  3062. return ShaderManager()->CreatePixelShader( pBuffer );
  3063. }
  3064. void CShaderDeviceDx8::DestroyPixelShader( PixelShaderHandle_t hShader )
  3065. {
  3066. ShaderManager()->DestroyPixelShader( hShader );
  3067. }
  3068. #ifdef DX_TO_GL_ABSTRACTION
  3069. void CShaderDeviceDx8::DoStartupShaderPreloading( void )
  3070. {
  3071. ShaderManager()->DoStartupShaderPreloading();
  3072. }
  3073. #endif
  3074. //-----------------------------------------------------------------------------
  3075. // Creates/destroys Mesh
  3076. // NOTE: Will be deprecated soon!
  3077. //-----------------------------------------------------------------------------
  3078. IMesh* CShaderDeviceDx8::CreateStaticMesh( VertexFormat_t vertexFormat, const char *pTextureBudgetGroup, IMaterial * pMaterial )
  3079. {
  3080. LOCK_SHADERAPI();
  3081. return MeshMgr()->CreateStaticMesh( vertexFormat, pTextureBudgetGroup, pMaterial );
  3082. }
  3083. void CShaderDeviceDx8::DestroyStaticMesh( IMesh* pMesh )
  3084. {
  3085. LOCK_SHADERAPI();
  3086. MeshMgr()->DestroyStaticMesh( pMesh );
  3087. }
  3088. //-----------------------------------------------------------------------------
  3089. // Creates/destroys vertex buffers + index buffers
  3090. //-----------------------------------------------------------------------------
  3091. IVertexBuffer *CShaderDeviceDx8::CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup )
  3092. {
  3093. LOCK_SHADERAPI();
  3094. return MeshMgr()->CreateVertexBuffer( type, fmt, nVertexCount, pBudgetGroup );
  3095. }
  3096. void CShaderDeviceDx8::DestroyVertexBuffer( IVertexBuffer *pVertexBuffer )
  3097. {
  3098. LOCK_SHADERAPI();
  3099. MeshMgr()->DestroyVertexBuffer( pVertexBuffer );
  3100. }
  3101. IIndexBuffer *CShaderDeviceDx8::CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup )
  3102. {
  3103. LOCK_SHADERAPI();
  3104. return MeshMgr()->CreateIndexBuffer( bufferType, fmt, nIndexCount, pBudgetGroup );
  3105. }
  3106. void CShaderDeviceDx8::DestroyIndexBuffer( IIndexBuffer *pIndexBuffer )
  3107. {
  3108. LOCK_SHADERAPI();
  3109. MeshMgr()->DestroyIndexBuffer( pIndexBuffer );
  3110. }
  3111. IVertexBuffer *CShaderDeviceDx8::GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered )
  3112. {
  3113. LOCK_SHADERAPI();
  3114. return MeshMgr()->GetDynamicVertexBuffer( streamID, vertexFormat, bBuffered );
  3115. }
  3116. IIndexBuffer *CShaderDeviceDx8::GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered )
  3117. {
  3118. LOCK_SHADERAPI();
  3119. return MeshMgr()->GetDynamicIndexBuffer( fmt, bBuffered );
  3120. }
  3121. #ifdef _X360
  3122. void CShaderDeviceDx8::SpewVideoInfo360( const CCommand &args )
  3123. {
  3124. XVIDEO_MODE videoMode;
  3125. XGetVideoMode( &videoMode );
  3126. Warning( "back buffer size: %dx%d\n", m_PresentParameters.BackBufferWidth, m_PresentParameters.BackBufferHeight );
  3127. Warning( "display resolution: %dx%d %s\n", videoMode.dwDisplayWidth, videoMode.dwDisplayHeight, videoMode.fIsInterlaced ? "interlaced" : "progressive" );
  3128. Warning( "refresh rate: %f\n", videoMode.RefreshRate );
  3129. Warning( "aspect: %s\n", videoMode.fIsWideScreen ? "16x9 (widescreen)" : "4x3 (normal)" );
  3130. Warning( "%s\n", videoMode.fIsHiDef ? "hidef" : "lodef" );
  3131. switch( videoMode.VideoStandard )
  3132. {
  3133. case XC_VIDEO_STANDARD_NTSC_M:
  3134. Warning( "video standard: NTSC_M\n" );
  3135. break;
  3136. case XC_VIDEO_STANDARD_NTSC_J:
  3137. Warning( "video standard: NTSC_J\n" );
  3138. break;
  3139. case XC_VIDEO_STANDARD_PAL_I:
  3140. Warning( "video standard: PAL_I\n" );
  3141. break;
  3142. default:
  3143. Warning( "error: UNKNOWN VIDEO STANDARD!\n" );
  3144. Assert( 0 );
  3145. break;
  3146. }
  3147. ConVarRef fps_max( "fps_max" );
  3148. Warning( "fps_max: %f\n", fps_max.GetFloat() );
  3149. switch( m_PresentParameters.MultiSampleType )
  3150. {
  3151. case D3DMULTISAMPLE_NONE:
  3152. Warning( "multisample type: D3DMULTISAMPLE_NONE\n" );
  3153. break;
  3154. case D3DMULTISAMPLE_2_SAMPLES:
  3155. Warning( "multisample type: D3DMULTISAMPLE_2_SAMPLES\n" );
  3156. break;
  3157. case D3DMULTISAMPLE_4_SAMPLES:
  3158. Warning( "multisample type: D3DMULTISAMPLE_4_SAMPLES\n" );
  3159. break;
  3160. }
  3161. }
  3162. #endif