Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

17690 lines
565 KiB

  1. //======Copyright (c) Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //
  6. // The dx8 implementation of the shader API
  7. //==================================================================//
  8. /*
  9. DX9 todo:
  10. -make the transforms in the older shaders match the transforms in lightmappedgeneric
  11. -fix polyoffset for hardware that doesn't support D3DRS_SLOPESCALEDEPTHBIAS and D3DRS_DEPTHBIAS
  12. - code is there, I think matrix offset just needs tweaking
  13. -fix forcehardwaresync - implement texture locking for hardware that doesn't support async query
  14. -get the format for GetAdapterModeCount and EnumAdapterModes from somewhere (shaderapidx8.cpp, GetModeCount, GetModeInfo)
  15. -record frame sync objects (allocframesyncobjects, free framesync objects, ForceHardwareSync)
  16. -Need to fix ENVMAPMASKSCALE, BUMPOFFSET in lightmappedgeneric*.cpp and vertexlitgeneric*.cpp
  17. fix this:
  18. // FIXME: This also depends on the vertex format and whether or not we are static lit in dx9
  19. #ifndef SHADERAPIDX9
  20. if (m_DynamicState.m_VertexShader != shader) // garymcthack
  21. #endif // !SHADERAPIDX9
  22. unrelated to dx9:
  23. mat_fullbright 1 doesn't work properly on alpha materials in testroom_standards
  24. */
  25. #include "shaderapidx8.h"
  26. #include "shaderapidx8_global.h"
  27. #include "shadershadowdx8.h"
  28. #include "locald3dtypes.h"
  29. #include "utlvector.h"
  30. #include "IHardwareConfigInternal.h"
  31. #include "utlstack.h"
  32. #include "shaderapi/ishaderutil.h"
  33. #include "shaderapi/commandbuffer.h"
  34. #include "shaderapi/gpumemorystats.h"
  35. #include "shaderapidx8_global.h"
  36. #include "materialsystem/imaterialsystem.h"
  37. #include "materialsystem/itexture.h"
  38. #include "imaterialinternal.h"
  39. #include "imeshdx8.h"
  40. #include "materialsystem/imorph.h"
  41. #include "colorformatdx8.h"
  42. #include "texturedx8.h"
  43. #include "textureheap.h"
  44. #if !defined ( _PS3 )
  45. #include <malloc.h>
  46. #endif // !_PS3
  47. #include "interface.h"
  48. #include "utlrbtree.h"
  49. #include "utlsymbol.h"
  50. #include "tier1/strtools.h"
  51. #include "recording.h"
  52. #ifndef _X360
  53. #include <crtmemdebug.h>
  54. #endif
  55. #include "vertexshaderdx8.h"
  56. #include "filesystem.h"
  57. #include "mathlib/mathlib.h"
  58. #include "materialsystem/materialsystem_config.h"
  59. #include "worldsize.h"
  60. #include "TransitionTable.h"
  61. #include "tier0/perfstats.h"
  62. #include "tier0/vprof.h"
  63. #include "tier1/tier1.h"
  64. #include "tier1/utlbuffer.h"
  65. #include "vertexdecl.h"
  66. #include "tier0/icommandline.h"
  67. #include "materialsystem/ishadersystem.h"
  68. #include "tier1/convar.h"
  69. #include "tier1/keyvalues.h"
  70. #include "vstdlib/vstrtools.h"
  71. #include "color.h"
  72. #ifdef RECORDING
  73. #include "materialsystem/IShader.h"
  74. #endif
  75. #include "../stdshaders/common_hlsl_cpp_consts.h" // hack hack hack!
  76. #include "keyvalues.h"
  77. #include "bitmap/imageformat.h"
  78. #include "materialsystem/idebugtextureinfo.h"
  79. #include "tier1/utllinkedlist.h"
  80. #include "vtf/vtf.h"
  81. #include "datacache/idatacache.h"
  82. #include "renderparm.h"
  83. #include "tier2/tier2.h"
  84. #include "materialsystem/deformations.h"
  85. #include "bitmap/tgawriter.h"
  86. #include "itextureinternal.h"
  87. #include "texturemanager.h"
  88. #include "bitmap/imageformat.h"
  89. #include "togl/rendermechanism.h"
  90. #if defined( _X360 )
  91. #include "xbox/xbox_console.h"
  92. #include "xbox/xbox_vxconsole.h"
  93. #include "xbox/xbox_win32stubs.h"
  94. #include "xbox/xbox_launch.h"
  95. #endif
  96. #include "tier0/tslist.h"
  97. #ifndef _X360
  98. #include "wmi.h"
  99. #endif
  100. #include "filesystem/IQueuedLoader.h"
  101. #include "shaderdevicedx8.h"
  102. #include "utldict.h"
  103. #ifdef _PS3
  104. #include "ps3gcm\gcmdrawstate.h"
  105. #include "ps3gcm\gcmtexture.h"
  106. #endif
  107. // Define this if you want to use a stubbed d3d.
  108. //#define STUBD3D
  109. #ifdef STUBD3D
  110. #include "stubd3ddevice.h"
  111. #endif
  112. #include "winutils.h"
  113. #ifdef _WIN32
  114. #include "nvapi.h"
  115. #include "NvApiDriverSettings.h"
  116. #endif
  117. #include "winutils.h"
  118. // memdbgon must be the last include file in a .cpp file!!!
  119. #include "tier0/memdbgon.h"
  120. #ifdef _WIN32
  121. #pragma warning (disable:4189)
  122. #endif
  123. #if ( ( defined( _WIN32 ) || defined( LINUX ) ) && ( !defined( DYNAMIC_SHADER_COMPILE ) ) )
  124. ConVar mat_vtxlit_new_path( "mat_vtxlit_new_path", "1", FCVAR_DEVELOPMENTONLY );
  125. ConVar mat_unlit_new_path( "mat_unlit_new_path", "1", FCVAR_DEVELOPMENTONLY );
  126. ConVar mat_lmap_new_path( "mat_lmap_new_path", "1", FCVAR_DEVELOPMENTONLY );
  127. ConVar mat_depthwrite_new_path( "mat_depthwrite_new_path", "1", FCVAR_DEVELOPMENTONLY );
  128. CON_COMMAND( toggleVtxLitPath, "toggleVtxLitPath" )
  129. {
  130. mat_vtxlit_new_path.SetValue( !mat_vtxlit_new_path.GetBool() );
  131. Msg( "mat_vtxlit_new_path = %s\n", mat_vtxlit_new_path.GetBool()? "TRUE":"FALSE" );
  132. }
  133. CON_COMMAND( toggleUnlitPath, "toggleUnlitPath" )
  134. {
  135. mat_unlit_new_path.SetValue( !mat_unlit_new_path.GetBool() );
  136. Msg( "mat_unlit_new_path = %s\n", mat_unlit_new_path.GetBool()? "TRUE":"FALSE" );
  137. }
  138. CON_COMMAND( toggleLmapPath, "toggleLmapPath" )
  139. {
  140. mat_lmap_new_path.SetValue( !mat_lmap_new_path.GetBool() );
  141. Msg( "toggleLmapPath = %s\n", mat_lmap_new_path.GetBool()? "TRUE":"FALSE" );
  142. }
  143. CON_COMMAND( toggleShadowPath, "Toggles CSM generation method" )
  144. {
  145. mat_depthwrite_new_path.SetValue( !mat_depthwrite_new_path.GetBool() );
  146. Msg( "mat_depthwrite_new_path = %s\n", mat_depthwrite_new_path.GetBool()? "TRUE":"FALSE" );
  147. }
  148. #else
  149. ConVar mat_vtxlit_new_path( "mat_vtxlit_new_path", "0", FCVAR_DEVELOPMENTONLY );
  150. ConVar mat_unlit_new_path( "mat_unlit_new_path", "0", FCVAR_DEVELOPMENTONLY );
  151. ConVar mat_lmap_new_path( "mat_lmap_new_path", "0", FCVAR_DEVELOPMENTONLY );
  152. ConVar mat_depthwrite_new_path( "mat_depthwrite_new_path", "0", FCVAR_DEVELOPMENTONLY );
  153. #endif
  154. // On OSX, this does
  155. #ifdef _OSX
  156. ConVar r_frameratesmoothing( "r_frameratesmoothing", "1", FCVAR_ARCHIVE, "Enable frame rate smoothing, which significantly reduces stutters but at the expense of overall frame rate." );
  157. #else
  158. // This convar only does something on OSX, but is referenced from Windows and Linux. Just leave a dummy here for them to find.
  159. ConVar r_frameratesmoothing( "r_frameratesmoothing", "0", FCVAR_NONE, "", true, 0, true, 0 );
  160. #endif
  161. // If you need to debug refcounting issues, enable this. As of this writing, only Z side is
  162. // instrumented.
  163. // #define SPEW_REFCOUNTS 1
  164. #ifdef SPEW_REFCOUNTS
  165. #define SPEW_REFCOUNT_( f, l, funcname, pObj, op, expected ) \
  166. do { \
  167. if ( pObj == NULL ) { \
  168. Msg( "%s(%d): %s: %s == NULL\n", f, l, funcname, #pObj ); \
  169. break; \
  170. } \
  171. pObj->AddRef(); \
  172. ULONG rc = pObj->Release(); \
  173. Assert( rc op expected ); \
  174. Msg( "%s(%d): %s: ref( %s [0x%08p] ) -> %d\n", f, l, funcname, #pObj, pObj, rc ); \
  175. } while ( 0 )
  176. #define SPEW_REFCOUNT( pObj ) SPEW_REFCOUNT_( __FILE__, __LINE__, __FUNCTION__, pObj, >=, 0 ) // Unsigned, so everything is >= 0.
  177. #define SPEW_REFCOUNT_EXPECTED( pObj, op, expected ) SPEW_REFCOUNT_( __FILE__, __LINE__, __FUNCTION__, pObj, op, expected )
  178. #else
  179. #define SPEW_REFCOUNT_( f, l, funcname, pObj, op, expected ) \
  180. do { \
  181. if ( pObj == NULL ) { \
  182. break; \
  183. } \
  184. pObj->AddRef(); \
  185. ULONG rc = pObj->Release(); \
  186. Assert( rc op expected ); \
  187. } while ( 0 )
  188. #define SPEW_REFCOUNT( pObj ) /* nothing if we're not spewing */
  189. #define SPEW_REFCOUNT_EXPECTED( pObj, op, expected ) /* nothing if we're not spewing */
  190. #endif
  191. ConVar mat_texture_limit( "mat_texture_limit", "-1", FCVAR_NEVER_AS_STRING,
  192. "If this value is not -1, the material system will limit the amount of texture memory it uses in a frame."
  193. " Useful for identifying performance cliffs. The value is in kilobytes." );
  194. // This feature is useful because world static mesh size (in vertex count) is computed while the dynamic VBs are shrunk to save memory on map load/unload. Setting this
  195. // var to 1 will not shrink the VBs, which will increase the number of vertices allowed in a single batch.
  196. ConVar mat_do_not_shrink_dynamic_vb( "mat_do_not_shrink_dynamic_vb", "0", 0, "Do not shrink the size of dynamic vertex buffers during map load/unload to save memory." );
  197. ConVar mat_frame_sync_enable( "mat_frame_sync_enable", "1", FCVAR_CHEAT );
  198. ConVar mat_frame_sync_force_texture( "mat_frame_sync_force_texture", "0", FCVAR_CHEAT, "Force frame syncing to lock a managed texture." );
  199. #if defined( _X360 )
  200. ConVar mat_x360_vblank_miss_threshold( "mat_x360_vblank_miss_threshold", "8" );
  201. #endif
  202. static ConVar r_pixelfog( "r_pixelfog", "1" );
  203. ConVar r_force_first_dynamic_light_to_directional_for_csm( "r_force_first_dynamic_light_to_directional_for_csm", "1", FCVAR_CHEAT|FCVAR_DEVELOPMENTONLY, "" );
  204. #if defined( _X360 )
  205. ConVar mat_texturecachesize( "mat_texturecachesize", "176" );
  206. ConVar mat_force_flush_texturecache( "mat_force_flush_texturecache", "0" );
  207. ConVar mat_hi_z_enable( "mat_hi_z_enable", "1", FCVAR_CHEAT, "Toggle Hi-Z on the Xbox 360" );
  208. ConVar mat_hi_stencil_enable( "mat_hi_stencil_enable", "1", FCVAR_CHEAT, "Toggle Hi-Stencil on the Xbox 360" );
  209. #if defined( CSTRIKE15 )
  210. static ConVar r_shader_srgbread( "r_shader_srgbread", "1", 0, "1 = use shader srgb texture reads, 0 = use HW" );
  211. #else
  212. static ConVar r_shader_srgbread( "r_shader_srgbread", "0", 0, "1 = use shader srgb texture reads, 0 = use HW" );
  213. #endif
  214. #endif
  215. extern ConVar mat_debugalttab;
  216. #define ALLOW_SMP_ACCESS 0
  217. #if ALLOW_SMP_ACCESS
  218. static ConVar mat_use_smp( "mat_use_smp", "0" );
  219. #endif
  220. // [mhansen] Enable PIX in debug and profile builds (Xbox 360 only)
  221. // PC: By default, PIX profiling is explicitly disallowed using the D3DPERF_SetOptions(1) API on PC
  222. // X360: PIX_INSTRUMENTATION will only generate PIX events in RELEASE builds on 360
  223. // Uncomment to use PIX instrumentation:
  224. #if defined( _X360) && (defined( PROFILE_BUILD ) || defined( _DEBUG ))
  225. #define PIX_INSTRUMENTATION
  226. #endif
  227. // Convars for driving PIX (not all hooked up yet...JasonM)
  228. static ConVar r_pix_start( "r_pix_start", "0" );
  229. static ConVar r_pix_recordframes( "r_pix_recordframes", "0" );
  230. #if defined( _X360 )
  231. #define JUNE_2009_XDK_ISSUES
  232. #endif
  233. //-----------------------------------------------------------------------------
  234. // Some important enumerations
  235. //-----------------------------------------------------------------------------
  236. enum
  237. {
  238. MAX_VERTEX_TEXTURE_COUNT = 4,
  239. };
  240. //-----------------------------------------------------------------------------
  241. // These board states change with high frequency; are not shadowed
  242. //-----------------------------------------------------------------------------
  243. struct SamplerState_t
  244. {
  245. ShaderAPITextureHandle_t m_BoundTexture;
  246. D3DTEXTUREADDRESS m_UTexWrap;
  247. D3DTEXTUREADDRESS m_VTexWrap;
  248. D3DTEXTUREADDRESS m_WTexWrap;
  249. D3DTEXTUREFILTERTYPE m_MagFilter;
  250. D3DTEXTUREFILTERTYPE m_MinFilter;
  251. D3DTEXTUREFILTERTYPE m_MipFilter;
  252. TextureBindFlags_t m_nTextureBindFlags;
  253. int m_nAnisotropicLevel;
  254. uint m_bShadowFilterEnable;
  255. bool m_TextureEnable;
  256. };
  257. //-----------------------------------------------------------------------------
  258. // State related to vertex textures
  259. //-----------------------------------------------------------------------------
  260. struct VertexTextureState_t
  261. {
  262. ShaderAPITextureHandle_t m_BoundVertexTexture;
  263. D3DTEXTUREADDRESS m_UTexWrap;
  264. D3DTEXTUREADDRESS m_VTexWrap;
  265. D3DTEXTUREFILTERTYPE m_MagFilter;
  266. D3DTEXTUREFILTERTYPE m_MinFilter;
  267. D3DTEXTUREFILTERTYPE m_MipFilter;
  268. };
  269. enum TransformType_t
  270. {
  271. TRANSFORM_IS_IDENTITY = 0,
  272. TRANSFORM_IS_CAMERA_TO_WORLD,
  273. TRANSFORM_IS_GENERAL,
  274. };
  275. enum TransformDirtyBits_t
  276. {
  277. STATE_CHANGED_VERTEX_SHADER = 0x1,
  278. STATE_CHANGED = 0x1
  279. };
  280. struct UberlightRenderState_t
  281. {
  282. Vector4D m_vSmoothEdge0;
  283. Vector4D m_vSmoothEdge1;
  284. Vector4D m_vSmoothOneOverW;
  285. Vector4D m_vShearRound;
  286. Vector4D m_vaAbB;
  287. VMatrix m_WorldToLight;
  288. };
  289. struct DepthBiasState_t
  290. {
  291. float m_flOOSlopeScaleDepthBias;
  292. float m_flOODepthBias;
  293. };
  294. enum
  295. {
  296. #if !defined( _X360 )
  297. MAX_NUM_RENDERSTATES = ( D3DRS_BLENDOPALPHA+1 ),
  298. #else
  299. MAX_NUM_RENDERSTATES = D3DRS_MAX,
  300. #endif
  301. // MORPH_TARGET_FACTOR_COUNT = VERTEX_SHADER_MORPH_TARGET_FACTOR_COUNT * 4,
  302. };
  303. struct DynamicState_t
  304. {
  305. // Viewport state
  306. D3DVIEWPORT9 m_Viewport;
  307. // Transform state
  308. D3DXMATRIX m_Transform[NUM_MATRIX_MODES];
  309. unsigned char m_TransformType[NUM_MATRIX_MODES];
  310. unsigned char m_TransformChanged[NUM_MATRIX_MODES];
  311. InstanceInfo_t m_InstanceInfo;
  312. CompiledLightingState_t m_CompiledLightingState;
  313. MaterialLightingState_t m_LightingState;
  314. // Used for GetDx9LightState
  315. mutable LightState_t m_ShaderLightState;
  316. mutable bool m_bLightStateComputed;
  317. // Used to deal with env cubemaps
  318. int m_nLocalEnvCubemapSamplers;
  319. // Used to deal with lightmaps
  320. int m_nLightmapSamplers;
  321. int m_nPaintmapSamplers;
  322. // Shade mode
  323. D3DSHADEMODE m_ShadeMode;
  324. // Clear color
  325. D3DCOLOR m_ClearColor;
  326. // Fog
  327. D3DCOLOR m_FogColor;
  328. Vector4D m_vecPixelFogColor;
  329. Vector4D m_vecPixelFogColorLinear;
  330. bool m_bFogGammaCorrectionDisabled;
  331. bool m_FogEnable;
  332. D3DFOGMODE m_FogMode;
  333. float m_FogStart;
  334. float m_FogEnd;
  335. float m_FogZ;
  336. float m_FogMaxDensity;
  337. float m_HeightClipZ;
  338. MaterialHeightClipMode_t m_HeightClipMode;
  339. // user clip planes
  340. int m_UserClipPlaneEnabled;
  341. int m_UserClipPlaneChanged;
  342. D3DXPLANE m_UserClipPlaneWorld[MAXUSERCLIPPLANES];
  343. D3DXPLANE m_UserClipPlaneProj[MAXUSERCLIPPLANES];
  344. bool m_UserClipLastUpdatedUsingFixedFunction;
  345. bool m_FastClipEnabled;
  346. bool m_bFastClipPlaneChanged;
  347. D3DXPLANE m_FastClipPlane;
  348. // Used when overriding the user clip plane
  349. bool m_bUserClipTransformOverride;
  350. D3DXMATRIX m_UserClipTransform;
  351. // Cull mode
  352. D3DCULL m_DesiredCullMode;
  353. D3DCULL m_CullMode;
  354. bool m_bCullEnabled;
  355. // Skinning
  356. int m_NumBones;
  357. // Pixel and vertex shader constants...
  358. Vector4D* m_pVectorVertexShaderConstant;
  359. BOOL* m_pBooleanVertexShaderConstant;
  360. IntVector4D* m_pIntegerVertexShaderConstant;
  361. Vector4D* m_pVectorPixelShaderConstant;
  362. BOOL* m_pBooleanPixelShaderConstant;
  363. IntVector4D* m_pIntegerPixelShaderConstant;
  364. // Texture stage state
  365. SamplerState_t m_SamplerState[MAX_SAMPLERS];
  366. // Vertex texture stage state
  367. VertexTextureState_t m_VertexTextureState[MAX_VERTEX_TEXTURE_COUNT];
  368. DWORD m_RenderState[MAX_NUM_RENDERSTATES];
  369. RECT m_ScissorRect;
  370. IDirect3DVertexDeclaration9 *m_pVertexDecl;
  371. VertexFormat_t m_DeclVertexFormat;
  372. bool m_bDeclHasColorMesh;
  373. bool m_bDeclUsingFlex;
  374. bool m_bDeclUsingMorph;
  375. bool m_bDeclUsingPreTessPatch;
  376. bool m_bSRGBWritesEnabled;
  377. bool m_bHWMorphingEnabled;
  378. #if defined( _X360 )
  379. int m_iVertexShaderGPRAllocation; //only need to track vertex shader
  380. bool m_bBuffer2Frames;
  381. #endif
  382. TessellationMode_t m_TessellationMode;
  383. DynamicState_t() {}
  384. private:
  385. DynamicState_t( DynamicState_t const& );
  386. DISALLOW_OPERATOR_EQUAL( DynamicState_t );
  387. };
  388. //-----------------------------------------------------------------------------
  389. // Method to queue up dirty dynamic state change calls
  390. //-----------------------------------------------------------------------------
  391. typedef void (*StateCommitFunc_t)( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce );
  392. static void CommitSetViewports( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce );
  393. // NOTE: It's slightly memory inefficient, and definitely not typesafe,
  394. // to put all commit funcs into the same table (vs, per-draw, per-pass),
  395. // but it makes the code a heck of a lot simpler and smaller.
  396. enum CommitFunc_t
  397. {
  398. COMMIT_FUNC_CommitVertexTextures = 0,
  399. COMMIT_FUNC_CommitFlexWeights,
  400. COMMIT_FUNC_CommitSetScissorRect,
  401. COMMIT_FUNC_CommitSetViewports,
  402. #if defined( _X360 )
  403. COMMIT_FUNC_CommitShaderGPRs,
  404. #endif
  405. COMMIT_FUNC_COUNT,
  406. COMMIT_FUNC_BYTE_COUNT = ( COMMIT_FUNC_COUNT + 0x7 ) >> 3,
  407. };
  408. enum CommitFuncType_t
  409. {
  410. COMMIT_PER_DRAW = 0,
  411. COMMIT_PER_PASS,
  412. COMMIT_FUNC_TYPE_COUNT,
  413. };
  414. #define ADD_COMMIT_FUNC( _func, _func_name ) \
  415. if ( !IsCommitFuncInUse( _func, COMMIT_FUNC_ ## _func_name ) ) \
  416. { \
  417. AddCommitFunc( _func, _func_name ); \
  418. MarkCommitFuncInUse( _func, COMMIT_FUNC_ ## _func_name ); \
  419. }
  420. #define ADD_RENDERSTATE_FUNC( _func, _func_name, _state, _val ) \
  421. if ( m_bResettingRenderState || (m_DesiredState._state != _val) ) \
  422. { \
  423. m_DesiredState._state = _val; \
  424. ADD_COMMIT_FUNC( _func, _func_name ) \
  425. }
  426. #define ADD_VERTEX_TEXTURE_FUNC( _func, _func_name, _stage, _state, _val ) \
  427. Assert( _stage < MAX_VERTEX_TEXTURE_COUNT ); \
  428. if ( m_bResettingRenderState || (m_DesiredState.m_VertexTextureState[_stage]._state != _val) ) \
  429. { \
  430. m_DesiredState.m_VertexTextureState[_stage]._state = _val; \
  431. ADD_COMMIT_FUNC( _func, _func_name ) \
  432. }
  433. #if defined( _X360 )
  434. static void CommitShaderGPRs( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce );
  435. #endif
  436. //-----------------------------------------------------------------------------
  437. // Check render state support at compile time instead of runtime
  438. //-----------------------------------------------------------------------------
  439. #define SetSupportedRenderState( _state, _val ) \
  440. { \
  441. if( _state != D3DRS_NOTSUPPORTED ) \
  442. { \
  443. SetRenderState( _state, _val ); \
  444. } \
  445. }
  446. #define SetSupportedRenderStateForce( _state, _val ) \
  447. { \
  448. if( _state != D3DRS_NOTSUPPORTED ) \
  449. { \
  450. SetRenderStateForce( _state, _val ); \
  451. } \
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Allocated textures
  455. //-----------------------------------------------------------------------------
  456. struct Texture_t
  457. {
  458. Texture_t()
  459. {
  460. m_Flags = 0;
  461. m_Count = 1;
  462. m_CountIndex = 0;
  463. m_nTimesBoundMax = 0;
  464. m_nTimesBoundThisFrame = 0;
  465. m_pTexture = NULL;
  466. m_ppTexture = NULL;
  467. m_ImageFormat = IMAGE_FORMAT_RGBA8888;
  468. m_pTextureGroupCounterGlobal = NULL;
  469. m_pTextureGroupCounterFrame = NULL;
  470. }
  471. uint8 m_UTexWrap;
  472. uint8 m_VTexWrap;
  473. uint8 m_WTexWrap;
  474. uint8 m_MagFilter;
  475. uint8 m_MinFilter;
  476. uint8 m_MipFilter;
  477. uint8 m_NumLevels;
  478. uint8 m_SwitchNeeded; // Do we need to advance the current copy?
  479. uint8 m_NumCopies; // copies are used to optimize procedural textures
  480. uint8 m_CurrentCopy; // the current copy we're using...
  481. private:
  482. union
  483. {
  484. IDirect3DBaseTexture *m_pTexture; // used when there's one copy
  485. IDirect3DBaseTexture **m_ppTexture; // used when there are more than one copies
  486. IDirect3DSurface *m_pDepthStencilSurface; // used when there's one depth stencil surface
  487. IDirect3DSurface *m_pRenderTargetSurface[2]; // 360: regular+sRGB views onto an EDRAM surface
  488. };
  489. ImageFormat m_ImageFormat;
  490. public:
  491. int m_CreationFlags;
  492. CUtlSymbol m_DebugName;
  493. CUtlSymbol m_TextureGroupName;
  494. int *m_pTextureGroupCounterGlobal; // Global counter for this texture's group.
  495. int *m_pTextureGroupCounterFrame; // Per-frame global counter for this texture's group.
  496. // stats stuff
  497. int m_SizeBytes;
  498. int m_SizeTexels;
  499. int m_LastBoundFrame;
  500. int m_nTimesBoundMax;
  501. int m_nTimesBoundThisFrame;
  502. enum Flags_t
  503. {
  504. IS_ALLOCATED = 0x0001,
  505. IS_DEPTH_STENCIL = 0x0002,
  506. IS_DEPTH_STENCIL_TEXTURE = 0x0004, // depth stencil texture, not surface
  507. IS_RENDERABLE = ( IS_DEPTH_STENCIL | IS_ALLOCATED ),
  508. IS_FINALIZED = 0x0010, // CONSOLE: completed async hi-res load
  509. IS_ERROR_TEXTURE = 0x0020, // CONSOLE: failed during load
  510. CAN_CONVERT_FORMAT = 0x0040, // 360: allow format conversion
  511. IS_LINEAR = 0x0080, // 360: unswizzled linear format
  512. IS_RENDER_TARGET = 0x0100, // CONSOLE: marks a render target texture source
  513. IS_RENDER_TARGET_SURFACE = 0x0200, // 360: marks a render target surface target
  514. IS_VERTEX_TEXTURE = 0x0800,
  515. IS_PWL_CORRECTED = 0x1000, // 360: data is pwl corrected
  516. IS_CACHEABLE = 0x2000, // 360: texture is subject to cache discard
  517. };
  518. short m_Width;
  519. short m_Height;
  520. short m_Depth;
  521. unsigned short m_Flags;
  522. typedef IDirect3DBaseTexture *IDirect3DBaseTexturePtr;
  523. typedef IDirect3DBaseTexture **IDirect3DBaseTexturePtrPtr;
  524. typedef IDirect3DSurface *IDirect3DSurfacePtr;
  525. IDirect3DBaseTexturePtr GetTexture( void )
  526. {
  527. Assert( m_NumCopies == 1 );
  528. Assert( !( m_Flags & IS_DEPTH_STENCIL ) );
  529. return m_pTexture;
  530. }
  531. IDirect3DBaseTexturePtr GetTexture( int copy )
  532. {
  533. Assert( m_NumCopies > 1 );
  534. Assert( !( m_Flags & IS_DEPTH_STENCIL ) );
  535. return m_ppTexture[copy];
  536. }
  537. IDirect3DBaseTexturePtrPtr &GetTextureArray( void )
  538. {
  539. Assert( m_NumCopies > 1 );
  540. Assert( !( m_Flags & IS_DEPTH_STENCIL ) );
  541. return m_ppTexture;
  542. }
  543. IDirect3DSurfacePtr &GetDepthStencilSurface( void )
  544. {
  545. Assert( m_NumCopies == 1 );
  546. Assert( (m_Flags & IS_DEPTH_STENCIL) );
  547. return m_pDepthStencilSurface;
  548. }
  549. IDirect3DSurfacePtr &GetRenderTargetSurface( bool bSRGB )
  550. {
  551. Assert( IsX360() );
  552. Assert( m_NumCopies == 1 );
  553. Assert( m_Flags & IS_RENDER_TARGET_SURFACE );
  554. return m_pRenderTargetSurface[bSRGB?1:0];
  555. }
  556. void SetTexture( IDirect3DBaseTexturePtr pPtr )
  557. {
  558. m_pTexture = pPtr;
  559. }
  560. void SetTexture( int copy, IDirect3DBaseTexturePtr pPtr )
  561. {
  562. m_ppTexture[copy] = pPtr;
  563. }
  564. int GetMemUsage() const
  565. {
  566. return m_SizeBytes;
  567. }
  568. int GetWidth() const
  569. {
  570. return ( int )m_Width;
  571. }
  572. int GetHeight() const
  573. {
  574. return ( int )m_Height;
  575. }
  576. int GetDepth() const
  577. {
  578. return ( int )m_Depth;
  579. }
  580. void SetImageFormat( ImageFormat format )
  581. {
  582. m_ImageFormat = format;
  583. }
  584. ImageFormat GetImageFormat() const
  585. {
  586. return m_ImageFormat;
  587. }
  588. public:
  589. short m_Count;
  590. short m_CountIndex;
  591. short GetCount() const
  592. {
  593. return m_Count;
  594. }
  595. };
  596. #define MAX_DEFORMATION_PARAMETERS 16
  597. #define DEFORMATION_STACK_DEPTH 10
  598. struct Deformation_t
  599. {
  600. int m_nDeformationType;
  601. int m_nNumParameters;
  602. float m_flDeformationParameters[MAX_DEFORMATION_PARAMETERS];
  603. };
  604. // These represent the three different methods that we apply fog in the shader.
  605. enum FogMethod_t
  606. {
  607. FOGMETHOD_FIXEDFUNCTIONVERTEXFOG = 0,
  608. FOGMETHOD_VERTEXFOGBLENDEDINPIXELSHADER,
  609. FOGMETHOD_PIXELSHADERFOG,
  610. FOGMETHOD_NUMVALUES
  611. };
  612. //-----------------------------------------------------------------------------
  613. // The DX8 implementation of the shader API
  614. //-----------------------------------------------------------------------------
  615. class CShaderAPIDx8 : public CShaderDeviceDx8, public IShaderAPIDX8, public IDebugTextureInfo
  616. {
  617. typedef CShaderDeviceDx8 BaseClass;
  618. public:
  619. // constructor, destructor
  620. CShaderAPIDx8( );
  621. virtual ~CShaderAPIDx8();
  622. // Methods of IShaderAPI
  623. public:
  624. virtual void SetViewports( int nCount, const ShaderViewport_t* pViewports, bool setImmediately = false );
  625. virtual int GetViewports( ShaderViewport_t* pViewports, int nMax ) const;
  626. virtual void ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil, int renderTargetWidth, int renderTargetHeight );
  627. virtual void ClearColor3ub( unsigned char r, unsigned char g, unsigned char b );
  628. virtual void ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  629. virtual void BindVertexShader( VertexShaderHandle_t hVertexShader );
  630. virtual void BindGeometryShader( GeometryShaderHandle_t hGeometryShader );
  631. virtual void BindPixelShader( PixelShaderHandle_t hPixelShader );
  632. virtual void SetRasterState( const ShaderRasterState_t& state );
  633. virtual void SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t* pWeights );
  634. virtual void OnPresent( void );
  635. #ifdef _GAMECONSOLE
  636. // Backdoor used by the queued context to directly use write-combined memory
  637. virtual IMesh *GetExternalMesh( const ExternalMeshInfo_t& info );
  638. virtual void SetExternalMeshData( IMesh *pMesh, const ExternalMeshData_t &data );
  639. virtual IIndexBuffer *GetExternalIndexBuffer( int nIndexCount, uint16 *pIndexData );
  640. virtual void FlushGPUCache( void *pBaseAddr, size_t nSizeInBytes );
  641. #endif
  642. // Methods of IShaderDynamicAPI
  643. public:
  644. virtual void GetBackBufferDimensions( int &nWidth, int &nHeight ) const
  645. {
  646. // Chain to the device
  647. BaseClass::GetBackBufferDimensions( nWidth, nHeight );
  648. }
  649. virtual const AspectRatioInfo_t &GetAspectRatioInfo( void ) const
  650. {
  651. // Chain to the device
  652. return BaseClass::GetAspectRatioInfo();
  653. }
  654. // Get the dimensions of the current render target
  655. virtual void GetCurrentRenderTargetDimensions( int& nWidth, int& nHeight ) const
  656. {
  657. ITexture *pTexture = ShaderAPI()->GetRenderTargetEx( 0 );
  658. if ( pTexture == NULL )
  659. {
  660. ShaderAPI()->GetBackBufferDimensions( nWidth, nHeight );
  661. }
  662. else
  663. {
  664. nWidth = pTexture->GetActualWidth();
  665. nHeight = pTexture->GetActualHeight();
  666. }
  667. }
  668. // Get the current viewport
  669. virtual void GetCurrentViewport( int& nX, int& nY, int& nWidth, int& nHeight ) const
  670. {
  671. ShaderViewport_t viewport;
  672. ShaderAPI()->GetViewports( &viewport, 1 );
  673. nX = viewport.m_nTopLeftX;
  674. nY = viewport.m_nTopLeftY;
  675. nWidth = viewport.m_nWidth;
  676. nHeight = viewport.m_nHeight;
  677. }
  678. virtual void MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords );
  679. virtual void SetScreenSizeForVPOS( int pshReg = 32 );
  680. virtual void SetVSNearAndFarZ( int vshReg );
  681. virtual float GetFarZ();
  682. virtual void EnableSinglePassFlashlightMode( bool bEnable );
  683. virtual bool SinglePassFlashlightModeEnabled( void );
  684. public:
  685. // Methods of CShaderAPIBase
  686. virtual bool OnDeviceInit();
  687. virtual void OnDeviceShutdown();
  688. virtual void ReleaseShaderObjects( bool bReleaseManagedResources = true );
  689. virtual void RestoreShaderObjects();
  690. virtual void BeginPIXEvent( unsigned long color, const char *szName );
  691. virtual void EndPIXEvent();
  692. virtual void AdvancePIXFrame();
  693. virtual void NotifyShaderConstantsChangedInRenderPass();
  694. virtual void GenerateNonInstanceRenderState( MeshInstanceData_t *pInstance, CompiledLightingState_t** pCompiledState, InstanceInfo_t **pInstanceInfo );
  695. public:
  696. // Methods of IShaderAPIDX8
  697. virtual void QueueResetRenderState();
  698. //
  699. // Abandon all hope ye who pass below this line which hasn't been ported.
  700. //
  701. // Sets the mode...
  702. bool SetMode( void* VD3DHWND, int nAdapter, const ShaderDeviceInfo_t &info );
  703. // Change the video mode after it's already been set.
  704. void ChangeVideoMode( const ShaderDeviceInfo_t &info );
  705. // Sets the default render state
  706. void SetDefaultState();
  707. // Methods to ask about particular state snapshots
  708. virtual bool IsTranslucent( StateSnapshot_t id ) const;
  709. virtual bool IsAlphaTested( StateSnapshot_t id ) const;
  710. virtual bool UsesVertexAndPixelShaders( StateSnapshot_t id ) const;
  711. virtual int CompareSnapshots( StateSnapshot_t snapshot0, StateSnapshot_t snapshot1 );
  712. // Computes the vertex format for a particular set of snapshot ids
  713. VertexFormat_t ComputeVertexFormat( int num, StateSnapshot_t* pIds ) const;
  714. VertexFormat_t ComputeVertexUsage( int num, StateSnapshot_t* pIds ) const;
  715. // Uses a state snapshot
  716. void UseSnapshot( StateSnapshot_t snapshot );
  717. // Set the number of bone weights
  718. virtual void SetNumBoneWeights( int numBones );
  719. virtual void EnableHWMorphing( bool bEnable );
  720. // Sets the vertex and pixel shaders
  721. virtual void SetVertexShaderIndex( int vshIndex = -1 );
  722. virtual void SetPixelShaderIndex( int pshIndex = 0 );
  723. // Matrix state
  724. void MatrixMode( MaterialMatrixMode_t matrixMode );
  725. void PushMatrix();
  726. void PopMatrix();
  727. void LoadMatrix( float *m );
  728. void LoadBoneMatrix( int boneIndex, const float *m );
  729. void MultMatrix( float *m );
  730. void MultMatrixLocal( float *m );
  731. void GetMatrix( MaterialMatrixMode_t matrixMode, float *dst );
  732. void LoadIdentity( void );
  733. void LoadCameraToWorld( void );
  734. void Ortho( double left, double top, double right, double bottom, double zNear, double zFar );
  735. void PerspectiveX( double fovx, double aspect, double zNear, double zFar );
  736. void PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right );
  737. void PickMatrix( int x, int y, int width, int height );
  738. void Rotate( float angle, float x, float y, float z );
  739. void Translate( float x, float y, float z );
  740. void Scale( float x, float y, float z );
  741. void ScaleXY( float x, float y );
  742. // Binds a particular material to render with
  743. void Bind( IMaterial* pMaterial );
  744. IMaterialInternal* GetBoundMaterial();
  745. // Level of anisotropic filtering
  746. virtual void SetAnisotropicLevel( int nAnisotropyLevel );
  747. virtual void SyncToken( const char *pToken );
  748. void CullMode( MaterialCullMode_t cullMode );
  749. void FlipCullMode( void );
  750. // Force writes only when z matches. . . useful for stenciling things out
  751. // by rendering the desired Z values ahead of time.
  752. void ForceDepthFuncEquals( bool bEnable );
  753. // Turns off Z buffering
  754. void OverrideDepthEnable( bool bEnable, bool bDepthWriteEnable, bool bDepthTestEnable = true );
  755. void OverrideAlphaWriteEnable( bool bOverrideEnable, bool bAlphaWriteEnable );
  756. void OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable );
  757. void SetHeightClipZ( float z );
  758. void SetHeightClipMode( enum MaterialHeightClipMode_t heightClipMode );
  759. void SetClipPlane( int index, const float *pPlane );
  760. void EnableClipPlane( int index, bool bEnable );
  761. void SetFastClipPlane(const float *pPlane);
  762. void EnableFastClip(bool bEnable);
  763. // The shade mode
  764. void ShadeMode( ShaderShadeMode_t mode );
  765. // Gets the dynamic mesh
  766. IMesh* GetDynamicMesh( IMaterial* pMaterial, int nHWSkinBoneCount, bool buffered,
  767. IMesh* pVertexOverride, IMesh* pIndexOverride );
  768. IMesh* GetDynamicMeshEx( IMaterial* pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount,
  769. bool bBuffered, IMesh* pVertexOverride, IMesh* pIndexOverride );
  770. IMesh *GetFlexMesh();
  771. // Returns the number of vertices we can render using the dynamic mesh
  772. virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices );
  773. virtual int GetMaxVerticesToRender( IMaterial *pMaterial );
  774. virtual int GetMaxIndicesToRender( );
  775. // Draws the mesh
  776. void DrawMesh( CMeshBase* mesh, int nCount, const MeshInstanceData_t *pInstances, VertexCompressionType_t nCompressionType, CompiledLightingState_t* pCompiledState, InstanceInfo_t *pInfo );
  777. void DrawMesh2( CMeshBase* mesh, int nCount, const MeshInstanceData_t *pInstances, VertexCompressionType_t nCompressionType, CompiledLightingState_t* pCompiledState, InstanceInfo_t *pInfo );
  778. void DrawShadowMesh( CMeshBase* mesh, int nCount, const MeshInstanceData_t *pInstances, VertexCompressionType_t nCompressionType, CompiledLightingState_t* pCompiledState, InstanceInfo_t *pInfo );
  779. void DrawMeshInternal( CMeshBase* mesh, int nCount, const MeshInstanceData_t *pInstances, VertexCompressionType_t nCompressionType, CompiledLightingState_t* pCompiledState, InstanceInfo_t *pInfo );
  780. // Draws
  781. void BeginPass( StateSnapshot_t snapshot );
  782. void RenderPass( const unsigned char *pInstanceCommandBuffer, int nPass, int nPassCount );
  783. // We use smaller dynamic VBs during level transitions, to free up memory
  784. virtual int GetCurrentDynamicVBSize( void );
  785. virtual void DestroyVertexBuffers( bool bExitingLevel = false );
  786. void SetVertexDecl( VertexFormat_t vertexFormat, bool bHasColorMesh, bool bUsingFlex, bool bUsingMorph, bool bUsingPreTessPatch, VertexStreamSpec_t *pStreamSpec );
  787. void SetTessellationMode( TessellationMode_t mode );
  788. // Sets the constant register for vertex and pixel shaders
  789. FORCEINLINE void SetVertexShaderConstantInternal( int var, float const* pVec, int numVecs = 1, bool bForce = false );
  790. void SetVertexShaderConstant( int var, float const* pVec, int numVecs = 1, bool bForce = false );
  791. void SetBooleanVertexShaderConstant( int var, BOOL const* pVec, int numBools = 1, bool bForce = false );
  792. void SetIntegerVertexShaderConstant( int var, int const* pVec, int numIntVecs = 1, bool bForce = false );
  793. void SetPixelShaderConstant( int var, float const* pVec, int numVecs = 1, bool bForce = false );
  794. #ifdef _PS3
  795. FORCEINLINE void SetPixelShaderConstantInternal( int var, float const* pValues, int nNumConsts = 1, bool bForce = false )
  796. {
  797. Dx9Device()->SetPixelShaderConstantF( var, pValues, nNumConsts );
  798. }
  799. #else
  800. FORCEINLINE void SetPixelShaderConstantInternal( int var, float const* pValues, int nNumConsts = 1, bool bForce = false );
  801. #endif
  802. void SetBooleanPixelShaderConstant( int var, BOOL const* pVec, int numBools = 1, bool bForce = false );
  803. void SetIntegerPixelShaderConstant( int var, int const* pVec, int numIntVecs = 1, bool bForce = false );
  804. void InvalidateDelayedShaderConstants( void );
  805. // Returns the nearest supported format
  806. ImageFormat GetNearestSupportedFormat( ImageFormat fmt, bool bFilteringRequired = true ) const;
  807. ImageFormat GetNearestRenderTargetFormat( ImageFormat format ) const;
  808. virtual bool DoRenderTargetsNeedSeparateDepthBuffer() const;
  809. // stuff that shouldn't be used from within a shader
  810. void ModifyTexture( ShaderAPITextureHandle_t textureHandle );
  811. void BindTexture( Sampler_t sampler, TextureBindFlags_t nBindFlags, ShaderAPITextureHandle_t textureHandle );
  812. void BindVertexTexture( VertexTextureSampler_t nStage, ShaderAPITextureHandle_t textureHandle );
  813. void DeleteTexture( ShaderAPITextureHandle_t textureHandle );
  814. void WriteTextureToFile( ShaderAPITextureHandle_t hTexture, const char *szFileName );
  815. bool IsTexture( ShaderAPITextureHandle_t textureHandle );
  816. bool IsTextureResident( ShaderAPITextureHandle_t textureHandle );
  817. FORCEINLINE bool TextureIsAllocated( ShaderAPITextureHandle_t hTexture )
  818. {
  819. return m_Textures.IsValidIndex( hTexture ) && ( GetTexture( hTexture ).m_Flags & Texture_t::IS_ALLOCATED );
  820. }
  821. FORCEINLINE void AssertValidTextureHandle( ShaderAPITextureHandle_t textureHandle )
  822. {
  823. #ifdef _DEBUG
  824. Assert( TextureIsAllocated( textureHandle ) );
  825. #endif
  826. }
  827. // Lets the shader know about the full-screen texture so it can
  828. virtual void SetFullScreenTextureHandle( ShaderAPITextureHandle_t h );
  829. virtual void SetLinearToGammaConversionTextures( ShaderAPITextureHandle_t hSRGBWriteEnabledTexture, ShaderAPITextureHandle_t hIdentityTexture );
  830. // Set the render target to a texID.
  831. // Set to SHADER_RENDERTARGET_BACKBUFFER if you want to use the regular framebuffer.
  832. void SetRenderTarget( ShaderAPITextureHandle_t colorTextureHandle = SHADER_RENDERTARGET_BACKBUFFER,
  833. ShaderAPITextureHandle_t depthTextureHandle = SHADER_RENDERTARGET_DEPTHBUFFER );
  834. // Set the render target to a texID.
  835. // Set to SHADER_RENDERTARGET_BACKBUFFER if you want to use the regular framebuffer.
  836. void SetRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t colorTextureHandle = SHADER_RENDERTARGET_BACKBUFFER,
  837. ShaderAPITextureHandle_t depthTextureHandle = SHADER_RENDERTARGET_DEPTHBUFFER );
  838. // These are bound to the texture, not the texture environment
  839. void TexMinFilter( ShaderTexFilterMode_t texFilterMode );
  840. void TexMagFilter( ShaderTexFilterMode_t texFilterMode );
  841. void TexWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode );
  842. void TexSetPriority( int priority );
  843. ShaderAPITextureHandle_t CreateTextureHandle( void );
  844. void CreateTextureHandles( ShaderAPITextureHandle_t *handles, int count, bool bReuseHandles );
  845. ShaderAPITextureHandle_t CreateTexture(
  846. int width,
  847. int height,
  848. int depth,
  849. ImageFormat dstImageFormat,
  850. int numMipLevels,
  851. int numCopies,
  852. int creationFlags,
  853. const char *pDebugName,
  854. const char *pTextureGroupName );
  855. // Create a multi-frame texture (equivalent to calling "CreateTexture" multiple times, but more efficient)
  856. void CreateTextures(
  857. ShaderAPITextureHandle_t *pHandles,
  858. int count,
  859. int width,
  860. int height,
  861. int depth,
  862. ImageFormat dstImageFormat,
  863. int numMipLevels,
  864. int numCopies,
  865. int flags,
  866. const char *pDebugName,
  867. const char *pTextureGroupName );
  868. ShaderAPITextureHandle_t CreateDepthTexture(
  869. ImageFormat renderTargetFormat,
  870. int width,
  871. int height,
  872. const char *pDebugName,
  873. bool bTexture,
  874. bool bAliasDepthSurfaceOverColorX360 = false );
  875. void TexImage2D(
  876. int level,
  877. int cubeFaceID,
  878. ImageFormat dstFormat,
  879. int zOffset,
  880. int width,
  881. int height,
  882. ImageFormat srcFormat,
  883. bool bSrcIsTiled,
  884. void *imageData );
  885. void TexSubImage2D(
  886. int level,
  887. int cubeFaceID,
  888. int xOffset,
  889. int yOffset,
  890. int zOffset,
  891. int width,
  892. int height,
  893. ImageFormat srcFormat,
  894. int srcStride,
  895. bool bSrcIsTiled,
  896. void *imageData );
  897. bool TexLock( int level, int cubeFaceID, int xOffset, int yOffset, int width, int height, CPixelWriter& writer );
  898. void TexUnlock( );
  899. // Copy sysmem surface to default pool surface asynchronously
  900. void UpdateTexture( int xOffset, int yOffset, int w, int h, ShaderAPITextureHandle_t hDstTexture, ShaderAPITextureHandle_t hSrcTexture );
  901. void *LockTex( ShaderAPITextureHandle_t hTexture );
  902. void UnlockTex( ShaderAPITextureHandle_t hTexture );
  903. void UpdateDepthBiasState();
  904. // stuff that isn't to be used from within a shader
  905. // what's the best way to hide this? subclassing?
  906. virtual void ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth );
  907. virtual void ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth );
  908. virtual void PerformFullScreenStencilOperation( void );
  909. void ReadPixels( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat, ITexture *pRenderTargetTexture = NULL );
  910. void ReadPixelsAsync( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat, ITexture *pRenderTargetTexture = NULL, CThreadEvent *pPixelsReadEvent = NULL );
  911. void ReadPixelsAsyncGetResult( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat, CThreadEvent *pGetResultEvent = NULL );
  912. virtual void ReadPixels( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *data, ImageFormat dstFormat, int nDstStride );
  913. // Gets the current buffered state... (debug only)
  914. void GetBufferedState( BufferedState_t& state );
  915. // Make sure we finish drawing everything that has been requested
  916. void FlushHardware();
  917. // Use this to begin and end the frame
  918. void BeginFrame();
  919. void EndFrame();
  920. // Used to clear the transition table when we know it's become invalid.
  921. void ClearSnapshots();
  922. // returns the D3D interfaces....
  923. #if !defined( _GAMECONSOLE )
  924. FORCEINLINE D3DDeviceWrapper *Dx9Device() const
  925. {
  926. return (D3DDeviceWrapper*)&(m_DeviceWrapper);
  927. }
  928. #endif
  929. // Backward compat
  930. virtual int GetActualSamplerCount() const;
  931. virtual int StencilBufferBits() const;
  932. virtual bool IsAAEnabled() const; // Is antialiasing being used?
  933. virtual bool OnAdapterSet( );
  934. bool m_bAdapterSet;
  935. void UpdateFastClipUserClipPlane( void );
  936. bool ReadPixelsFromFrontBuffer() const;
  937. // returns the current time in seconds....
  938. double CurrentTime() const;
  939. // Get the current camera position in world space.
  940. void GetWorldSpaceCameraPosition( float* pPos ) const;
  941. void GetWorldSpaceCameraDirection( float* pDir ) const;
  942. // Fog methods
  943. void EnableFixedFunctionFog( bool bFogEnable );
  944. void FogStart( float fStart );
  945. void FogEnd( float fEnd );
  946. void FogMaxDensity( float flMaxDensity );
  947. void SetFogZ( float fogZ );
  948. void GetFogDistances( float *fStart, float *fEnd, float *fFogZ );
  949. void SceneFogMode( MaterialFogMode_t fogMode );
  950. MaterialFogMode_t GetSceneFogMode( );
  951. int GetPixelFogCombo( );//0 is either range fog, or no fog simulated with rigged range fog values. 1 is height fog
  952. void SceneFogColor3ub( unsigned char r, unsigned char g, unsigned char b );
  953. void GetSceneFogColor( unsigned char *rgb );
  954. void GetSceneFogColor( unsigned char *r, unsigned char *g, unsigned char *b );
  955. /// update the array of precalculated color values when state changes.
  956. void RegenerateFogConstants( void );
  957. Vector CalculateFogColorConstant( D3DCOLOR *pPackedColorOut, FogMethod_t fogMethod, ShaderFogMode_t fogMode,
  958. bool bDisableFogGammaCorrection, bool bSRGBWritesEnabled );
  959. // Selection mode methods
  960. int SelectionMode( bool selectionMode );
  961. void SelectionBuffer( unsigned int* pBuffer, int size );
  962. void ClearSelectionNames( );
  963. void LoadSelectionName( int name );
  964. void PushSelectionName( int name );
  965. void PopSelectionName();
  966. bool IsInSelectionMode() const;
  967. void RegisterSelectionHit( float minz, float maxz );
  968. void WriteHitRecord();
  969. // Binds a standard texture
  970. virtual void BindStandardTexture( Sampler_t sampler, TextureBindFlags_t nBindFlags, StandardTextureId_t id );
  971. virtual void BindStandardVertexTexture( VertexTextureSampler_t sampler, StandardTextureId_t id );
  972. virtual void GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id );
  973. virtual float GetSubDHeight();
  974. virtual bool IsStereoActiveThisFrame() const;
  975. bool m_bIsStereoActiveThisFrame;
  976. // Gets the lightmap dimensions
  977. virtual void GetLightmapDimensions( int *w, int *h );
  978. // Use this to get the mesh builder that allows us to modify vertex data
  979. CMeshBuilder* GetVertexModifyBuilder();
  980. virtual bool InFlashlightMode() const;
  981. virtual bool IsRenderingPaint() const;
  982. virtual bool InEditorMode() const;
  983. // Helper to get at the texture state stage
  984. SamplerState_t& SamplerState( int nSampler ) { return m_DynamicState.m_SamplerState[nSampler]; }
  985. const SamplerState_t& SamplerState( int nSampler ) const { return m_DynamicState.m_SamplerState[nSampler]; }
  986. TextureBindFlags_t LastSetTextureBindFlags( int nSampler ) const { return SamplerState( nSampler ).m_nTextureBindFlags; }
  987. void SetLastSetTextureBindFlags( int nSampler, TextureBindFlags_t nBindFlags ) { SamplerState( nSampler ).m_nTextureBindFlags = nBindFlags; }
  988. virtual void SetLightingState( const MaterialLightingState_t& state );
  989. void SetLights( int nCount, const LightDesc_t *pDesc );
  990. void SetLightingOrigin( Vector vLightingOrigin );
  991. void DisableAllLocalLights();
  992. void SetAmbientLightCube( Vector4D colors[6] );
  993. float GetAmbientLightCubeLuminance( MaterialLightingState_t *pLightingState );
  994. void SetVertexShaderStateAmbientLightCube( int nVSReg, CompiledLightingState_t *pLightingState );
  995. void SetPixelShaderStateAmbientLightCube( int pshReg, CompiledLightingState_t *pLightingState );
  996. // Methods related to compiling lighting state for use in shaderes
  997. void CompileAmbientCube( CompiledLightingState_t *pCompiledState, int nLightCount, const MaterialLightingState_t *pLightingState );
  998. void CompileVertexShaderLocalLights( CompiledLightingState_t *pCompiledState, int nLightCount, const MaterialLightingState_t *pLightingState, bool bStaticLight );
  999. void CompilePixelShaderLocalLights( CompiledLightingState_t *pCompiledState, int nLightCount, const MaterialLightingState_t *pLightingState, bool bStaticLight );
  1000. void CopyRenderTargetToTexture( ShaderAPITextureHandle_t textureHandle );
  1001. void CopyRenderTargetToTextureEx( ShaderAPITextureHandle_t textureHandle, int nRenderTargetID, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL );
  1002. void CopyTextureToRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t textureHandle, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL );
  1003. // Returns the cull mode (for fill rate computation)
  1004. D3DCULL GetCullMode() const;
  1005. void SetCullModeState( bool bEnable, D3DCULL nDesiredCullMode );
  1006. void ApplyCullEnable( bool bEnable );
  1007. void FlipCulling( bool bFlipCulling );
  1008. // Alpha to coverage
  1009. void ApplyAlphaToCoverage( bool bEnable );
  1010. // Applies Z Bias
  1011. void ApplyZBias( const DepthTestState_t &shaderState );
  1012. // Applies texture enable
  1013. void ApplyTextureEnable( const ShadowState_t& state, int stage );
  1014. void ApplyFogMode( ShaderFogMode_t fogMode, bool bVertexFog, bool bSRGBWritesEnabled, bool bDisableFogGammaCorrection );
  1015. void UpdatePixelFogColorConstant( bool bMultiplyByToneMapScale = true );
  1016. void EnabledSRGBWrite( bool bEnabled );
  1017. void SetSRGBWrite( bool bState );
  1018. // Gamma<->Linear conversions according to the video hardware we're running on
  1019. float GammaToLinear_HardwareSpecific( float fGamma ) const;
  1020. float LinearToGamma_HardwareSpecific( float fLinear ) const;
  1021. // Applies alpha blending
  1022. void ApplyAlphaBlend( bool bEnable, D3DBLEND srcBlend, D3DBLEND destBlend );
  1023. // Sets texture stage stage + render stage state
  1024. void SetSamplerState( int stage, D3DSAMPLERSTATETYPE state, DWORD val );
  1025. void SetRenderStateForce( D3DRENDERSTATETYPE state, DWORD val );
  1026. void SetRenderState( D3DRENDERSTATETYPE state, DWORD val );
  1027. // Scissor Rect
  1028. void SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor );
  1029. // Can we download textures?
  1030. virtual bool CanDownloadTextures() const;
  1031. void ForceHardwareSync_WithManagedTexture();
  1032. void ForceHardwareSync( void );
  1033. void UpdateFrameSyncQuery( int queryIndex, bool bIssue );
  1034. void EvictManagedResources();
  1035. // Get stats on GPU memory usage
  1036. virtual void GetGPUMemoryStats( GPUMemoryStats &stats );
  1037. virtual void EvictManagedResourcesInternal();
  1038. // Gets at a particular transform
  1039. inline D3DXMATRIX& GetTransform( int i )
  1040. {
  1041. return *m_pMatrixStack[i]->GetTop();
  1042. }
  1043. int GetCurrentNumBones( void ) const;
  1044. bool IsHWMorphingEnabled( ) const;
  1045. TessellationMode_t GetTessellationMode( ) const;
  1046. void GetDX9LightState( LightState_t *state ) const; // Used for DX9 only
  1047. MaterialFogMode_t GetCurrentFogType( void ) const; // deprecated. don't use.
  1048. void RecordString( const char *pStr );
  1049. virtual bool IsRenderingMesh() const { return m_nRenderInstanceCount != 0; }
  1050. int GetCurrentFrameCounter( void ) const
  1051. {
  1052. return m_CurrentFrame;
  1053. }
  1054. // Workaround hack for visualization of selection mode
  1055. virtual void SetupSelectionModeVisualizationState();
  1056. // Allocate and delete query objects.
  1057. virtual ShaderAPIOcclusionQuery_t CreateOcclusionQueryObject( void );
  1058. virtual void DestroyOcclusionQueryObject( ShaderAPIOcclusionQuery_t h );
  1059. // Bracket drawing with begin and end so that we can get counts next frame.
  1060. virtual void BeginOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t h );
  1061. virtual void EndOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t h );
  1062. // Get the number of pixels rendered between begin and end on an earlier frame.
  1063. // Calling this in the same frame is a huge perf hit!
  1064. virtual int OcclusionQuery_GetNumPixelsRendered( ShaderAPIOcclusionQuery_t h, bool bFlush );
  1065. void SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture );
  1066. void SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture );
  1067. const FlashlightState_t &GetFlashlightState( VMatrix &worldToTexture ) const;
  1068. const FlashlightState_t &GetFlashlightStateEx( VMatrix &worldToTexture, ITexture **pFlashlightDepthTexture ) const;
  1069. virtual void GetFlashlightShaderInfo( bool *pShadowsEnabled, bool *pUberLight ) const;
  1070. virtual float GetFlashlightAmbientOcclusion( ) const;
  1071. virtual bool IsCascadedShadowMapping() const;
  1072. virtual void SetCascadedShadowMappingState( const CascadedShadowMappingState_t &state, ITexture *pDepthTextureAtlas );
  1073. virtual const CascadedShadowMappingState_t &GetCascadedShadowMappingState( ITexture **pDepthTextureAtlas, bool bLightMapScale = false ) const;
  1074. // Gets at the shadow state for a particular state snapshot
  1075. virtual bool IsDepthWriteEnabled( StateSnapshot_t id ) const;
  1076. // IDebugTextureInfo implementation.
  1077. virtual bool IsDebugTextureListFresh( int numFramesAllowed = 1 );
  1078. virtual void EnableDebugTextureList( bool bEnable );
  1079. virtual bool SetDebugTextureRendering( bool bEnable );
  1080. virtual void EnableGetAllTextures( bool bEnable );
  1081. virtual KeyValues* LockDebugTextureList( void );
  1082. virtual void UnlockDebugTextureList( void );
  1083. virtual int GetTextureMemoryUsed( TextureMemoryType eTextureMemory );
  1084. virtual void ClearVertexAndPixelShaderRefCounts();
  1085. virtual void PurgeUnusedVertexAndPixelShaders();
  1086. // Called when the dx support level has changed
  1087. virtual void DXSupportLevelChanged( int nDXLevel );
  1088. // User clip plane override
  1089. virtual void EnableUserClipTransformOverride( bool bEnable );
  1090. virtual void UserClipTransform( const VMatrix &worldToProjection );
  1091. bool UsingSoftwareVertexProcessing() const;
  1092. // Mark all user clip planes as being dirty
  1093. void MarkAllUserClipPlanesDirty();
  1094. // Converts a D3DXMatrix to a VMatrix and back
  1095. void D3DXMatrixToVMatrix( const D3DXMATRIX &in, VMatrix &out );
  1096. void VMatrixToD3DXMatrix( const VMatrix &in, D3DXMATRIX &out );
  1097. ITexture *GetRenderTargetEx( int nRenderTargetID ) const;
  1098. virtual void SetToneMappingScaleLinear( const Vector &scale );
  1099. virtual const Vector &GetToneMappingScaleLinear( void ) const;
  1100. void SetFloatRenderingParameter(int parm_number, float value); // Rendering Parameter Setters
  1101. void SetIntRenderingParameter(int parm_number, int value); //
  1102. void SetTextureRenderingParameter(int parm_number, ITexture *pTexture); //
  1103. void SetVectorRenderingParameter(int parm_number, Vector const &value); //
  1104. float GetFloatRenderingParameter(int parm_number) const; // Rendering Parameter Getters
  1105. int GetIntRenderingParameter(int parm_number) const; //
  1106. ITexture *GetTextureRenderingParameter(int parm_number) const; //
  1107. Vector GetVectorRenderingParameter(int parm_number) const; //
  1108. // For dealing with device lost in cases where Present isn't called all the time (Hammer)
  1109. virtual void HandleDeviceLost();
  1110. virtual void EnableLinearColorSpaceFrameBuffer( bool bEnable );
  1111. void SetStencilState( const ShaderStencilState_t &state ); // Stencil methods
  1112. void SetStencilStateInternal( const ShaderStencilState_t &state );
  1113. void GetCurrentStencilState( ShaderStencilState_t *pState );
  1114. void ClearStencilBufferRectangle(int xmin, int ymin, int xmax, int ymax,int value);
  1115. #if defined ( _GAMECONSOLE )
  1116. bool PostQueuedTexture( const void *pData, int nSize, ShaderAPITextureHandle_t *pHandles, int nHandles, int nWidth, int nHeight, int nDepth, int nMips, int *pRefCount );
  1117. #endif
  1118. #if defined( _X360 )
  1119. HXUIFONT OpenTrueTypeFont( const char *pFontname, int tall, int style );
  1120. void CloseTrueTypeFont( HXUIFONT hFont );
  1121. bool GetTrueTypeFontMetrics( HXUIFONT hFont, wchar_t wchFirst, wchar_t wchLast, XUIFontMetrics *pFontMetrics, XUICharMetrics *pCharMetrics );
  1122. // Render a sequence of characters and extract the data into a buffer
  1123. // For each character, provide the width+height of the font texture subrect,
  1124. // an offset to apply when rendering the glyph, and an offset into a buffer to receive the RGBA data
  1125. bool GetTrueTypeGlyphs( HXUIFONT hFont, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int *pWidth, int *pHeight, unsigned char *pRGBA, int *pRGBAOffset );
  1126. ShaderAPITextureHandle_t CreateRenderTargetSurface( int width, int height, ImageFormat format, RTMultiSampleCount360_t multiSampleCount, const char *pDebugName, const char *pTextureGroupName );
  1127. void PersistDisplay();
  1128. void *GetD3DDevice();
  1129. void PushVertexShaderGPRAllocation( int iVertexShaderCount = 64 );
  1130. void PopVertexShaderGPRAllocation( void );
  1131. void EnableVSync_360( bool bEnable );
  1132. virtual void SetCacheableTextureParams( ShaderAPITextureHandle_t *pHandles, int count, const char *pFilename, int mipSkipCount );
  1133. virtual void FlushHiStencil();
  1134. #endif
  1135. #if defined( _GAMECONSOLE )
  1136. virtual void BeginConsoleZPass2( int nNumDynamicIndicesNeeded );
  1137. virtual void EndConsoleZPass();
  1138. virtual unsigned int GetConsoleZPassCounter() const { return m_nZPassCounter; }
  1139. virtual void EnablePredication( bool bZPass, bool bRenderPass );
  1140. virtual void DisablePredication();
  1141. #endif
  1142. #if defined( _PS3 )
  1143. virtual void FlushTextureCache();
  1144. #endif
  1145. virtual void AntiAliasingHint( int nHint );
  1146. virtual bool OwnGPUResources( bool bEnable );
  1147. // ------------ New Vertex/Index Buffer interface ----------------------------
  1148. void BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 );
  1149. void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes );
  1150. void Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount );
  1151. // Draw the mesh with the currently bound vertex and index buffers.
  1152. void DrawWithVertexAndIndexBuffers( void );
  1153. // ------------ End ----------------------------
  1154. // deformations
  1155. virtual void PushDeformation( const DeformationBase_t *pDeformation );
  1156. virtual void PopDeformation( );
  1157. virtual int GetNumActiveDeformations( ) const ;
  1158. // for shaders to set vertex shader constants. returns a packed state which can be used to set the dynamic combo
  1159. virtual int GetPackedDeformationInformation( int nMaskOfUnderstoodDeformations,
  1160. float *pConstantValuesOut,
  1161. int nBufferSize,
  1162. int nMaximumDeformations,
  1163. int *pNumDefsOut ) const ;
  1164. inline Texture_t &GetTexture( ShaderAPITextureHandle_t hTexture )
  1165. {
  1166. return m_Textures[hTexture];
  1167. }
  1168. // Gets the texture
  1169. IDirect3DBaseTexture* GetD3DTexture( ShaderAPITextureHandle_t hTexture );
  1170. virtual void* GetD3DTexturePtr( ShaderAPITextureHandle_t hTexture );
  1171. virtual bool IsStandardTextureHandleValid( StandardTextureId_t textureId );
  1172. #ifdef _PS3
  1173. virtual void GetPs3Texture(void* tex, ShaderAPITextureHandle_t hTexture );
  1174. virtual void GetPs3Texture(void* tex, StandardTextureId_t nTextureId );
  1175. #endif
  1176. virtual bool ShouldWriteDepthToDestAlpha( void ) const;
  1177. virtual void AcquireThreadOwnership();
  1178. virtual void ReleaseThreadOwnership();
  1179. virtual void UpdateGameTime( float flTime ) { m_flCurrGameTime = flTime; }
  1180. virtual bool IsStereoSupported() const;
  1181. virtual void UpdateStereoTexture( ShaderAPITextureHandle_t texHandle, bool *pStereoActiveThisFrame );
  1182. #ifndef _PS3
  1183. private:
  1184. #endif
  1185. enum
  1186. {
  1187. SMALL_BACK_BUFFER_SURFACE_WIDTH = 256,
  1188. SMALL_BACK_BUFFER_SURFACE_HEIGHT = 256,
  1189. };
  1190. bool m_bEnableDebugTextureList;
  1191. bool m_bDebugGetAllTextures;
  1192. bool m_bDebugTexturesRendering;
  1193. KeyValues *m_pDebugTextureList;
  1194. CThreadFastMutex m_DebugTextureListLock;
  1195. int m_nTextureMemoryUsedLastFrame, m_nTextureMemoryUsedTotal;
  1196. int m_nTextureMemoryUsedPicMip1, m_nTextureMemoryUsedPicMip2;
  1197. int m_nDebugDataExportFrame;
  1198. FlashlightState_t m_FlashlightState;
  1199. VMatrix m_FlashlightWorldToTexture;
  1200. ITexture *m_pFlashlightDepthTexture;
  1201. UberlightRenderState_t m_UberlightRenderState;
  1202. float m_pFlashlightAtten[4];
  1203. float m_pFlashlightPos[4];
  1204. float m_pFlashlightColor[4];
  1205. float m_pFlashlightTweaks[4];
  1206. DepthBiasState_t m_ZBias;
  1207. DepthBiasState_t m_ZBiasDecal;
  1208. CascadedShadowMappingState_t m_CascadedShadowMappingState;
  1209. CascadedShadowMappingState_t m_CascadedShadowMappingState_LightMapScaled;
  1210. ITexture *m_pCascadedShadowMappingDepthTexture;
  1211. CShaderAPIDx8( CShaderAPIDx8 const& );
  1212. enum
  1213. {
  1214. INVALID_TRANSITION_OP = 0xFFFF
  1215. };
  1216. // State transition table for the device is as follows:
  1217. // Other app init causes transition from OK to OtherAppInit, during transition we must release resources
  1218. // !Other app init causes transition from OtherAppInit to OK, during transition we must restore resources
  1219. // Minimized or device lost or device not reset causes transition from OK to LOST_DEVICE, during transition we must release resources
  1220. // Minimized or device lost or device not reset causes transition from OtherAppInit to LOST_DEVICE
  1221. // !minimized AND !device lost causes transition from LOST_DEVICE to NEEDS_RESET
  1222. // minimized or device lost causes transition from NEEDS_RESET to LOST_DEVICE
  1223. // Successful TryDeviceReset and !Other app init causes transition from NEEDS_RESET to OK, during transition we must restore resources
  1224. // Successful TryDeviceReset and Other app init causes transition from NEEDS_RESET to OtherAppInit
  1225. void ExportTextureList();
  1226. void AddBufferToTextureList( const char *pName, D3DSURFACE_DESC &desc );
  1227. int D3DFormatToBitsPerPixel( D3DFORMAT fmt ) const;
  1228. void SetupTextureGroup( ShaderAPITextureHandle_t hTexture, const char *pTextureGroupName );
  1229. // Creates the matrix stack
  1230. void CreateMatrixStacks();
  1231. // Initializes the render state
  1232. void InitRenderState( );
  1233. // Resets all dx renderstates to dx default so that our shadows are correct.
  1234. void ResetDXRenderState( );
  1235. // Resets the render state
  1236. void ResetRenderState( bool bFullReset = true );
  1237. // Setup standard vertex shader constants (that don't change)
  1238. void SetStandardVertexShaderConstants( float fOverbright );
  1239. // Initializes vertex and pixel shaders
  1240. void InitVertexAndPixelShaders();
  1241. // Discards the vertex and index buffers
  1242. void DiscardVertexBuffers();
  1243. // Computes the fill rate
  1244. void ComputeFillRate();
  1245. // Takes a snapshot
  1246. virtual StateSnapshot_t TakeSnapshot( );
  1247. // Converts the clear color to be appropriate for HDR
  1248. D3DCOLOR GetActualClearColor( D3DCOLOR clearColor );
  1249. // We lost the device
  1250. void OnDeviceLost();
  1251. // Gets the matrix stack from the matrix mode
  1252. int GetMatrixStack( MaterialMatrixMode_t mode ) const;
  1253. // Flushes the matrix state, returns false if we don't need to
  1254. // do any more work
  1255. bool MatrixIsChanging( TransformType_t transform = TRANSFORM_IS_GENERAL );
  1256. // Updates the matrix transform state
  1257. void UpdateMatrixTransform( TransformType_t transform = TRANSFORM_IS_GENERAL );
  1258. // Sets the vertex shader modelView state..
  1259. // NOTE: GetProjectionMatrix should only be called from the Commit functions!
  1260. const D3DXMATRIX &GetProjectionMatrix( void );
  1261. void SetVertexShaderViewProj();
  1262. void SetVertexShaderModelViewProjAndModelView();
  1263. void SetPixelShaderFogParams( int reg );
  1264. void SetPixelShaderFogParams( int reg, ShaderFogMode_t fogMode );
  1265. void SetVertexShaderCameraPos()
  1266. {
  1267. float vertexShaderCameraPos[4];
  1268. vertexShaderCameraPos[0] = m_WorldSpaceCameraPosition[0];
  1269. vertexShaderCameraPos[1] = m_WorldSpaceCameraPosition[1];
  1270. vertexShaderCameraPos[2] = m_WorldSpaceCameraPosition[2];
  1271. vertexShaderCameraPos[3] = m_DynamicState.m_FogZ; //waterheight in water fog mode
  1272. // eyepos.x eyepos.y eyepos.z cWaterZ
  1273. SetVertexShaderConstantInternal( VERTEX_SHADER_CAMERA_POS, vertexShaderCameraPos );
  1274. }
  1275. // This is where vertex shader constants are set for both hardware vertex fog and pixel shader-blended vertex fog.
  1276. FORCEINLINE void UpdateVertexShaderFogParams( ShaderFogMode_t fogMode = SHADER_FOGMODE_NUMFOGMODES, bool bVertexFog = false )
  1277. {
  1278. float fogParams[4];
  1279. if( fogMode == SHADER_FOGMODE_NUMFOGMODES ) //not passing in an explicit fog mode
  1280. {
  1281. if ( m_TransitionTable.CurrentShadowState() == NULL )
  1282. {
  1283. fogMode = SHADER_FOGMODE_DISABLED;
  1284. bVertexFog = false;
  1285. }
  1286. else
  1287. {
  1288. fogMode = ( ShaderFogMode_t ) m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_FogMode;
  1289. bVertexFog = m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_bVertexFogEnable;
  1290. }
  1291. }
  1292. if( (m_SceneFogMode != MATERIAL_FOG_NONE) && (fogMode != SHADER_FOGMODE_DISABLED) )
  1293. {
  1294. //prepare the values for Fixed Function fog, and we'll modify them to handle pixel fog if necessary
  1295. float ooFogRange = 1.0f;
  1296. float fStart = m_VertexShaderFogParams[0];
  1297. float fEnd = m_VertexShaderFogParams[1];
  1298. // Check for divide by zero
  1299. if ( fEnd != fStart )
  1300. {
  1301. ooFogRange = 1.0f / ( fEnd - fStart );
  1302. }
  1303. // Fixed-function-blended per-vertex fog requires some inverted params since a fog factor of 0 means fully fogged and 1 means no fog.
  1304. // We could implement shader fog the same way, but would require an extra subtract in the vertex and/or pixel shader, which we want to avoid.
  1305. if ( HardwareConfig()->GetDXSupportLevel() <= 90 )
  1306. {
  1307. fogParams[0] = ooFogRange * fEnd;
  1308. fogParams[1] = 0.0f;
  1309. fogParams[2] = 1.0f - clamp( m_flFogMaxDensity, 0.0f, 1.0f ); // Max fog density
  1310. fogParams[3] = ooFogRange;
  1311. }
  1312. else
  1313. {
  1314. fogParams[0] = 1.0f - ( ooFogRange * fEnd );
  1315. fogParams[1] = 0.0f;
  1316. fogParams[2] = clamp( m_flFogMaxDensity, 0.0f, 1.0f ); // Max fog density
  1317. fogParams[3] = ooFogRange;
  1318. }
  1319. }
  1320. else
  1321. {
  1322. // Fixed-function-blended per-vertex fog requires some inverted params since a fog factor of 0 means fully fogged and 1 means no fog.
  1323. // We could implement shader fog the same way, but would require an extra subtract in the vertex and/or pixel shader, which we want to avoid.
  1324. if ( HardwareConfig()->GetDXSupportLevel() <= 90 )
  1325. {
  1326. //emulate no-fog by rigging the result to always be 0.
  1327. fogParams[0] = 1.0f;
  1328. fogParams[1] = -FLT_MAX;
  1329. fogParams[2] = 1.0f; //Max fog density
  1330. fogParams[3] = 0.0f; //0 out distance factor
  1331. }
  1332. else
  1333. {
  1334. //emulate no-fog by rigging the result to always be 0.
  1335. fogParams[0] = 0.0f;
  1336. fogParams[1] = -FLT_MAX;
  1337. fogParams[2] = 0.0f; //Max fog density
  1338. fogParams[3] = 0.0f; //0 out distance factor
  1339. }
  1340. }
  1341. // cFogEndOverFogRange, cFogOne, unused, cOOFogRange
  1342. SetVertexShaderConstantInternal( VERTEX_SHADER_FOG_PARAMS, fogParams, 1 );
  1343. SetVertexShaderCameraPos();
  1344. }
  1345. // Compute stats info for a texture
  1346. void ComputeStatsInfo( ShaderAPITextureHandle_t hTexture, bool bIsCubeMap, bool isVolumeTexture );
  1347. // For procedural textures
  1348. void AdvanceCurrentCopy( ShaderAPITextureHandle_t hTexture );
  1349. // Deletes a D3D texture
  1350. void DeleteD3DTexture( ShaderAPITextureHandle_t hTexture );
  1351. // Unbinds a texture
  1352. void UnbindTexture( ShaderAPITextureHandle_t hTexture );
  1353. // Releases all D3D textures
  1354. void ReleaseAllTextures();
  1355. // Deletes all textures
  1356. void DeleteAllTextures();
  1357. // Gets the currently modified texture handle
  1358. ShaderAPITextureHandle_t GetModifyTextureHandle() const;
  1359. // Gets the bind id
  1360. ShaderAPITextureHandle_t GetBoundTextureBindId( Sampler_t sampler ) const;
  1361. // If mat_texture_limit is enabled, then this tells us if binding the specified texture would
  1362. // take us over the limit.
  1363. bool WouldBeOverTextureLimit( ShaderAPITextureHandle_t hTexture );
  1364. // Sets the texture state
  1365. void SetTextureState( Sampler_t sampler, TextureBindFlags_t nBindFlags, ShaderAPITextureHandle_t hTexture, bool force = false );
  1366. FORCEINLINE void TouchTexture( Sampler_t sampler, IDirect3DBaseTexture *pD3DTexture );
  1367. // Lookup standard texture handle
  1368. ShaderAPITextureHandle_t GetStandardTextureHandle(StandardTextureId_t id);
  1369. // Grab/release the internal render targets such as the back buffer and the save game thumbnail
  1370. void AcquireInternalRenderTargets();
  1371. void ReleaseInternalRenderTargets();
  1372. // create/release linear->gamma table texture lookups. Only used by hardware supporting pixel shader 2b and up
  1373. void AcquireLinearToGammaTableTextures();
  1374. void ReleaseLinearToGammaTableTextures();
  1375. // Gets the texture being modified
  1376. IDirect3DBaseTexture* GetModifyTexture();
  1377. void SetModifyTexture( IDirect3DBaseTexture *pTex );
  1378. // returns true if we're using texture coordinates at a given stage
  1379. bool IsUsingTextureCoordinates( int stage, int flags ) const;
  1380. // Debugging spew
  1381. void SpewBoardState();
  1382. // Compute and save the world space camera position and direction
  1383. void CacheWorldSpaceCamera();
  1384. // Compute and save the projection atrix with polyoffset built in if we need it.
  1385. void CachePolyOffsetProjectionMatrix();
  1386. // Vertex shader helper functions
  1387. int FindVertexShader( VertexFormat_t fmt, const char* pFileName ) const;
  1388. int FindPixelShader( const char* pFileName ) const;
  1389. // Returns copies of the front and back buffers
  1390. IDirect3DSurface* GetFrontBufferImage( ImageFormat& format );
  1391. IDirect3DSurface* GetBackBufferImage( Rect_t *pSrcRect, Rect_t *pDstRect, ImageFormat& format );
  1392. IDirect3DSurface* GetBackBufferImageHDR( Rect_t *pSrcRect, Rect_t *pDstRect, ImageFormat& format );
  1393. // Copy bits from a host-memory surface
  1394. void CopyBitsFromHostSurface( IDirect3DSurface* pSurfaceBits,
  1395. const Rect_t &dstRect, unsigned char *pData, ImageFormat srcFormat, ImageFormat dstFormat, int nDstStride );
  1396. void SetTextureFilterMode( Sampler_t sampler, TextureFilterMode_t nMode );
  1397. void ExecuteCommandBuffer( uint8 *pCmdBuffer );
  1398. #ifdef _PS3
  1399. void ExecuteCommandBufferPPU(uint8 *pCmdBuffer );
  1400. #endif
  1401. void ExecuteInstanceCommandBuffer( const unsigned char *pCmdBuf, int nInstanceIndex, bool bForceStateSet );
  1402. void SetStandardTextureHandle( StandardTextureId_t nId, ShaderAPITextureHandle_t );
  1403. void RecomputeAggregateLightingState( void );
  1404. virtual void DrawInstances( int nInstanceCount, const MeshInstanceData_t *pInstance );
  1405. // Methods related to queuing functions to be called per-(pMesh->Draw call) or per-pass
  1406. void ClearAllCommitFuncs( CommitFuncType_t func );
  1407. bool IsCommitFuncInUse( CommitFuncType_t func, int nFunc ) const;
  1408. void MarkCommitFuncInUse( CommitFuncType_t func, int nFunc );
  1409. void AddCommitFunc( CommitFuncType_t func, StateCommitFunc_t f );
  1410. void CallCommitFuncs( CommitFuncType_t func, bool bForce = false );
  1411. // Commits transforms and lighting
  1412. void CommitStateChanges();
  1413. // Commits transforms that have to be dealt with on a per pass basis (ie. projection matrix for polyoffset)
  1414. void CommitPerPassStateChanges( StateSnapshot_t id );
  1415. // Need to handle fog mode on a per-pass basis
  1416. void CommitPerPassFogMode( bool bUsingVertexAndPixelShaders );
  1417. void CommitPerPassXboxFixups();
  1418. // Commits user clip planes
  1419. void CommitUserClipPlanes( );
  1420. // Gets the user clip transform (world->view)
  1421. D3DXMATRIX & GetUserClipTransform( );
  1422. // transform commit
  1423. bool VertexShaderTransformChanged( int i );
  1424. void UpdateVertexShaderMatrix( int iMatrix );
  1425. void CommitVertexShaderTransforms();
  1426. void CommitPerPassVertexShaderTransforms();
  1427. // Recomputes the fast-clip plane matrices based on the current fast-clip plane
  1428. void CommitFastClipPlane( );
  1429. // Computes a matrix which includes the poly offset given an initial projection matrix
  1430. void ComputePolyOffsetMatrix( const D3DXMATRIX& matProjection, D3DXMATRIX &matProjectionOffset );
  1431. bool SetSkinningMatrices( const MeshInstanceData_t &instance );
  1432. bool IsRenderingInstances() const;
  1433. // lighting commit
  1434. void CommitVertexShaderLighting( CompiledLightingState_t *pLightingState );
  1435. void CommitPixelShaderLighting( int pshReg, CompiledLightingState_t *pLightingState );
  1436. // Gets the surface associated with a texture (refcount of surface is increased)
  1437. IDirect3DSurface* GetTextureSurface( ShaderAPITextureHandle_t textureHandle );
  1438. IDirect3DSurface* GetDepthTextureSurface( ShaderAPITextureHandle_t textureHandle );
  1439. //
  1440. // Methods related to hardware config
  1441. //
  1442. void SetDefaultConfigValuesForDxLevel( int dxLevelFromCaps, ShaderDeviceInfo_t &info, unsigned int nFlagsUsed );
  1443. // Determines hardware capabilities
  1444. bool DetermineHardwareCaps( );
  1445. // Alpha To Coverage entrypoints and states - much of this involves vendor-dependent paths and states...
  1446. bool CheckVendorDependentAlphaToCoverage();
  1447. void EnableAlphaToCoverage();
  1448. void DisableAlphaToCoverage();
  1449. // Vendor-dependent shadow mapping detection
  1450. void CheckVendorDependentShadowMappingSupport( bool &bSupportsShadowDepthTextures, bool &bSupportsFetch4 );
  1451. // Override caps based on a requested dx level
  1452. void OverrideCaps( int nForcedDXLevel );
  1453. // Reports support for a given MSAA mode
  1454. bool SupportsMSAAMode( int nMSAAMode );
  1455. // Reports support for a given CSAA mode
  1456. bool SupportsCSAAMode( int nNumSamples, int nQualityLevel );
  1457. // Gamma correction of fog color, or not...
  1458. D3DCOLOR ComputeGammaCorrectedFogColor( unsigned char r, unsigned char g, unsigned char b, bool bSRGBWritesEnabled );
  1459. bool RestorePersistedDisplay( bool bUseFrontBuffer );
  1460. void ClearStdTextureHandles( void );
  1461. // debug logging
  1462. void PrintfVA( char *fmt, va_list vargs );
  1463. void Printf( char *fmt, ... );
  1464. float Knob( char *knobname, float *setvalue = NULL );
  1465. void AddShaderComboInformation( const ShaderComboSemantics_t *pSemantics );
  1466. virtual float GetLightMapScaleFactor() const;
  1467. virtual ShaderAPITextureHandle_t FindTexture( const char *pDebugName );
  1468. virtual void GetTextureDimensions( ShaderAPITextureHandle_t hTexture, int &nWidth, int &nHeight, int &nDepth );
  1469. #ifndef _GAMECONSOLE
  1470. D3DDeviceWrapper m_DeviceWrapper;
  1471. #endif
  1472. // "normal" back buffer and depth buffer. Need to keep this around so that we
  1473. // know what to set the render target to when we are done rendering to a texture.
  1474. CUtlVector<IDirect3DSurface*> m_pBackBufferSurfaces;
  1475. IDirect3DSurface *m_pBackBufferSurfaceSRGB;
  1476. IDirect3DSurface *m_pZBufferSurface;
  1477. // Optimization for screenshots
  1478. IDirect3DSurface *m_pSmallBackBufferFP16TempSurface;
  1479. ShaderAPITextureHandle_t m_hFullScreenTexture;
  1480. ShaderAPITextureHandle_t m_hLinearToGammaTableTexture;
  1481. ShaderAPITextureHandle_t m_hLinearToGammaTableIdentityTexture;
  1482. //
  1483. // State needed at the time of rendering (after snapshots have been applied)
  1484. //
  1485. // Interface for the D3DXMatrixStack
  1486. ID3DXMatrixStack* m_pMatrixStack[NUM_MATRIX_MODES];
  1487. matrix3x4_t m_boneMatrix[NUM_MODEL_TRANSFORMS];
  1488. int m_maxBoneLoaded;
  1489. // Current matrix mode
  1490. D3DTRANSFORMSTATETYPE m_MatrixMode;
  1491. int m_CurrStack;
  1492. // The current camera position in world space.
  1493. Vector m_WorldSpaceCameraPosition;
  1494. Vector m_WorldSpaceCameraDirection;
  1495. // The current projection matrix with polyoffset baked into it.
  1496. D3DXMATRIX m_CachedPolyOffsetProjectionMatrix;
  1497. D3DXMATRIX m_CachedFastClipProjectionMatrix;
  1498. D3DXMATRIX m_CachedFastClipPolyOffsetProjectionMatrix;
  1499. // The texture stage state that changes frequently
  1500. DynamicState_t m_DynamicState;
  1501. // The *desired* dynamic state. Most dynamic state is committed into actual hardware state
  1502. // at either per-pass or per-material time. This can also be used to force the hardware
  1503. // to match the desired state after returning from alt-tab.
  1504. DynamicState_t m_DesiredState;
  1505. // A list of state commit functions to run as per-draw call commit time
  1506. unsigned char m_pCommitFlags[COMMIT_FUNC_TYPE_COUNT][ COMMIT_FUNC_BYTE_COUNT ];
  1507. CUtlVector< StateCommitFunc_t > m_CommitFuncs[COMMIT_FUNC_TYPE_COUNT];
  1508. // Render data
  1509. CMeshBase *m_pRenderMesh;
  1510. int m_nRenderInstanceCount;
  1511. const MeshInstanceData_t *m_pRenderInstances;
  1512. CompiledLightingState_t *m_pRenderCompiledState;
  1513. InstanceInfo_t *m_pRenderInstanceInfo;
  1514. ShaderStencilState_t m_RenderInitialStencilState;
  1515. bool m_bRenderHasSetStencil;
  1516. int m_nDynamicVBSize;
  1517. IMaterialInternal *m_pMaterial;
  1518. // Shadow depth bias states
  1519. float m_fShadowSlopeScaleDepthBias;
  1520. float m_fShadowDepthBias;
  1521. bool m_bReadPixelsEnabled : 1;
  1522. bool m_bFlipCulling : 1;
  1523. bool m_bSinglePassFlashlightMode : 1;
  1524. bool m_UsingTextureRenderTarget : 1;
  1525. int m_ViewportMaxWidth;
  1526. int m_ViewportMaxHeight;
  1527. ShaderAPITextureHandle_t m_hCachedRenderTarget;
  1528. bool m_bUsingSRGBRenderTarget;
  1529. // The current frame
  1530. int m_CurrentFrame;
  1531. // The texture we're currently modifying
  1532. // Using thread local variables so that ModifyTexture(), TexLock()/TexUnlock(), ... can concurently be used
  1533. // from different thread (eg scaleform and lightmap)
  1534. static CTHREADLOCALINTEGER( ShaderAPITextureHandle_t ) m_ModifyTextureHandle;
  1535. static CTHREADLOCALINT m_ModifyTextureLockedLevel;
  1536. static CTHREADLOCALINT m_ModifyTextureLockedFace;
  1537. // Stores all textures
  1538. CUtlFixedLinkedList< Texture_t > m_Textures;
  1539. #ifdef _PS3
  1540. CUtlVector< ShaderAPITextureHandle_t > m_ArtificialTextureHandles;
  1541. struct DepthBufferCacheEntry_t
  1542. {
  1543. CPs3gcmTexture *m_pReal;
  1544. CPs3gcmTexture *m_pCache;
  1545. };
  1546. CUtlVector< DepthBufferCacheEntry_t > m_arrPs3DepthBufferCache;
  1547. #endif
  1548. float m_VertexShaderFogParams[2];
  1549. float m_flFogMaxDensity;
  1550. // Shadow state transition table
  1551. CTransitionTable m_TransitionTable;
  1552. StateSnapshot_t m_nCurrentSnapshot;
  1553. // Depth test override...
  1554. bool m_bOverrideMaterialIgnoreZ;
  1555. bool m_bIgnoreZValue;
  1556. // Are we in the middle of resetting the render state?
  1557. bool m_bResettingRenderState;
  1558. // Can we buffer 2 frames ahead?
  1559. bool m_bBuffer2FramesAhead;
  1560. // Selection name stack
  1561. CUtlStack< int > m_SelectionNames;
  1562. bool m_InSelectionMode;
  1563. unsigned int* m_pSelectionBufferEnd;
  1564. unsigned int* m_pSelectionBuffer;
  1565. unsigned int* m_pCurrSelectionRecord;
  1566. float m_SelectionMinZ;
  1567. float m_SelectionMaxZ;
  1568. int m_NumHits;
  1569. // fog
  1570. unsigned char m_SceneFogColor[3];
  1571. MaterialFogMode_t m_SceneFogMode;
  1572. // Tone Mapping state ( w is gamma scale )
  1573. Vector4D m_ToneMappingScale;
  1574. Deformation_t m_DeformationStack[DEFORMATION_STACK_DEPTH];
  1575. Deformation_t *m_pDeformationStackPtr;
  1576. void WriteShaderConstantsToGPU();
  1577. // rendering parameter storage
  1578. int IntRenderingParameters[MAX_INT_RENDER_PARMS];
  1579. ITexture *TextureRenderingParameters[MAX_TEXTURE_RENDER_PARMS];
  1580. float FloatRenderingParameters[MAX_FLOAT_RENDER_PARMS];
  1581. Vector VectorRenderingParameters[MAX_VECTOR_RENDER_PARMS];
  1582. ShaderAPITextureHandle_t m_StdTextureHandles[TEXTURE_MAX_STD_TEXTURES];
  1583. // PIX instrumentation utilities...enable these with PIX_INSTRUMENTATION
  1584. void StartPIXInstrumentation();
  1585. void EndPIXInstrumentation();
  1586. void SetPIXMarker( unsigned long color, const char *szName );
  1587. void IncrementPIXError();
  1588. bool PIXError();
  1589. int m_nPIXErrorCount;
  1590. int m_nPixFrame;
  1591. bool m_bPixCapturing;
  1592. void ComputeVertexDescription( unsigned char* pBuffer, VertexFormat_t vertexFormat, MeshDesc_t& desc ) const
  1593. {
  1594. return MeshMgr()->ComputeVertexDescription( pBuffer, vertexFormat, desc );
  1595. }
  1596. int VertexFormatSize( VertexFormat_t vertexFormat ) const
  1597. {
  1598. return MeshMgr()->VertexFormatSize( vertexFormat );
  1599. }
  1600. // Bracket custom shadow rendering code that doesn't use transition tables or regular cshaders
  1601. bool m_bToolsMode;
  1602. bool m_bVtxLitMesh;
  1603. bool m_bUnlitMesh;
  1604. bool m_bLmapMesh;
  1605. bool m_bGeneratingCSMs;
  1606. BOOL m_bCSMsValidThisFrame;
  1607. void BeginGeneratingCSMs();
  1608. void EndGeneratingCSMs();
  1609. // Per-cascade settings
  1610. void PerpareForCascadeDraw( int cascade, float fShadowSlopeScaleDepthBias, float fShadowDepthBias );
  1611. void SetShadowDepthBiasFactors( float fShadowSlopeScaleDepthBias, float fShadowDepthBias );
  1612. void EnableBuffer2FramesAhead( bool bEnable );
  1613. void GetActualProjectionMatrix( float *pMatrix );
  1614. void SetDepthFeatheringShaderConstants( int iConstant, float fDepthBlendScale );
  1615. void SetDisallowAccess( bool b )
  1616. {
  1617. g_bShaderAccessDisallowed = b;
  1618. }
  1619. void EnableShaderShaderMutex( bool b )
  1620. {
  1621. Assert( g_ShaderMutex.GetOwnerId() == 0 );
  1622. g_bUseShaderMutex = b;
  1623. }
  1624. void ShaderLock()
  1625. {
  1626. g_ShaderMutex.Lock();
  1627. }
  1628. void ShaderUnlock()
  1629. {
  1630. g_ShaderMutex.Unlock();
  1631. }
  1632. //The idea behind a delayed constant is this.
  1633. // Some shaders set constants based on rendering states, and some rendering states aren't updated until after a shader's already called Draw().
  1634. // So, for some functions that are state based, we save the constant we set and if the state changes between when it's set in the shader setup code
  1635. // and when the shader is drawn, we update that constant.
  1636. struct DelayedConstants_t
  1637. {
  1638. int iPixelShaderFogParams;
  1639. void Invalidate( void )
  1640. {
  1641. iPixelShaderFogParams = -1;
  1642. }
  1643. DelayedConstants_t( void ) { this->Invalidate(); }
  1644. };
  1645. DelayedConstants_t m_DelayedShaderConstants;
  1646. bool SetRenderTargetInternalXbox( ShaderAPITextureHandle_t hTexture, bool bForce = false );
  1647. FogMethod_t ComputeFogMethod( ShaderFogMode_t shaderFogMode, MaterialFogMode_t sceneFogMode, bool bVertexFog );
  1648. #if defined( _X360 )
  1649. CUtlStack<int> m_VertexShaderGPRAllocationStack;
  1650. #endif
  1651. int m_MaxVectorVertexShaderConstant;
  1652. int m_MaxBooleanVertexShaderConstant;
  1653. int m_MaxIntegerVertexShaderConstant;
  1654. int m_MaxVectorPixelShaderConstant;
  1655. int m_MaxBooleanPixelShaderConstant;
  1656. int m_MaxIntegerPixelShaderConstant;
  1657. bool m_bGPUOwned;
  1658. bool m_bResetRenderStateNeeded;
  1659. #if defined( _GAMECONSOLE )
  1660. bool m_bInZPass;
  1661. unsigned int m_nZPassCounter;
  1662. StateSnapshot_t m_zPassSnapshot;
  1663. #endif
  1664. float32 m_flCurrGameTime;
  1665. #if defined( _X360 )
  1666. struct XboxFontMap_t
  1667. {
  1668. XboxFontMap_t()
  1669. {
  1670. m_pPhysicalMemory = NULL;
  1671. m_nMemorySize = 0;
  1672. m_nFontFileSize = 0;
  1673. }
  1674. void *m_pPhysicalMemory;
  1675. int m_nMemorySize;
  1676. int m_nFontFileSize;
  1677. };
  1678. CUtlDict< XboxFontMap_t > m_XboxFontMemoryDict;
  1679. #endif
  1680. #if defined( _WIN32 )
  1681. IDirect3DSurface *m_pNVAPI_registeredDepthStencilSurface;
  1682. IDirect3DTexture *m_pNVAPI_registeredDepthTexture;
  1683. #endif
  1684. };
  1685. //-----------------------------------------------------------------------------
  1686. // Class Factory
  1687. //-----------------------------------------------------------------------------
  1688. static CShaderAPIDx8 g_ShaderAPIDX8;
  1689. IShaderAPIDX8 *g_pShaderAPIDX8 = &g_ShaderAPIDX8;
  1690. CShaderDeviceDx8* g_pShaderDeviceDx8 = &g_ShaderAPIDX8;
  1691. // FIXME: Remove IShaderAPI + IShaderDevice; they change after SetMode
  1692. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx8, IShaderAPI,
  1693. SHADERAPI_INTERFACE_VERSION, g_ShaderAPIDX8 )
  1694. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx8, IShaderDevice,
  1695. SHADER_DEVICE_INTERFACE_VERSION, g_ShaderAPIDX8 )
  1696. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx8, IDebugTextureInfo,
  1697. DEBUG_TEXTURE_INFO_VERSION, g_ShaderAPIDX8 )
  1698. //-----------------------------------------------------------------------------
  1699. // CShaderAPIDx8 static members
  1700. //-----------------------------------------------------------------------------
  1701. CTHREADLOCALINTEGER( ShaderAPITextureHandle_t ) CShaderAPIDx8::m_ModifyTextureHandle(INVALID_SHADERAPI_TEXTURE_HANDLE);
  1702. CTHREADLOCALINT CShaderAPIDx8::m_ModifyTextureLockedLevel(-1);
  1703. CTHREADLOCALINT CShaderAPIDx8::m_ModifyTextureLockedFace;
  1704. //-----------------------------------------------------------------------------
  1705. // Accessors for major interfaces
  1706. //-----------------------------------------------------------------------------
  1707. #if !defined( _GAMECONSOLE )
  1708. D3DDeviceWrapper *Dx9Device()
  1709. {
  1710. return g_ShaderAPIDX8.Dx9Device();
  1711. }
  1712. #endif
  1713. // Pix wants a max of 32 characters
  1714. // We'll give it the right-most substrings separated by slashes
  1715. static char s_pPIXMaterialName[32];
  1716. void PIXifyName( char *pDest, const char *pSrc )
  1717. {
  1718. char *pSrcWalk = (char *)pSrc;
  1719. // Walk forward looking for the end, find the last \ or /
  1720. char *pLastSlash = pSrcWalk;
  1721. while ( *pSrcWalk )
  1722. {
  1723. char c = *pSrcWalk;
  1724. if ( c == '\\' || c == '/' )
  1725. {
  1726. pLastSlash = pSrcWalk + 1;
  1727. }
  1728. ++pSrcWalk;
  1729. }
  1730. size_t nBytes = (intp)pSrcWalk - (intp)pLastSlash + 1;
  1731. if ( nBytes > 32 )
  1732. {
  1733. pLastSlash = pSrcWalk + 1 - 32;
  1734. nBytes = 32;
  1735. }
  1736. else if ( pLastSlash != pSrc )
  1737. {
  1738. pSrcWalk = pLastSlash - 2;
  1739. size_t nTestBytes = nBytes + 2;
  1740. while( nTestBytes <= 32 )
  1741. {
  1742. char c = *pSrcWalk;
  1743. if ( c == '\\' || c == '/' )
  1744. {
  1745. pLastSlash = pSrcWalk + 1;
  1746. nBytes = nTestBytes - 1;
  1747. }
  1748. if ( pSrcWalk == pSrc )
  1749. {
  1750. pLastSlash = (char*)pSrc;
  1751. nBytes = nTestBytes;
  1752. break;
  1753. }
  1754. --pSrcWalk;
  1755. ++nTestBytes;
  1756. }
  1757. }
  1758. memcpy( pDest, pLastSlash, nBytes );
  1759. }
  1760. #ifdef _WIN32
  1761. void PrintError( NvAPI_Status status, uint32 unStage, uint32 unProp, bool bPlus = false )
  1762. {
  1763. NvAPI_ShortString szDesc = { 0 };
  1764. NvAPI_GetErrorMessage( status, szDesc );
  1765. #ifdef DEBUG
  1766. Msg( " NVAPI error: %s\n", szDesc );
  1767. #endif
  1768. Error( "Failed to initialize NVidia driver!\nDriver error at 0x%08X%s%08X: %s\n\nPlease visit NVidia website to get the most recent version of the graphics drivers and restore your Counter-Strike: Global Offensive driver profile and global driver profile to NVidia defaults.",
  1769. unStage, ( bPlus ? "+" : "-" ), unProp,
  1770. szDesc );
  1771. }
  1772. #ifdef DEBUG
  1773. void DumpProfileSettings( NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, int numOfSettings )
  1774. {
  1775. char szTemp[ 2048 ];
  1776. size_t nChars = 0;
  1777. if ( numOfSettings > 0 )
  1778. {
  1779. NVDRS_SETTING *setArray = new NVDRS_SETTING[ numOfSettings ];
  1780. V_memset( setArray, 0, sizeof( NVDRS_SETTING ) * numOfSettings );
  1781. NvU32 numSetRead = numOfSettings;
  1782. setArray[ 0 ].version = NVDRS_SETTING_VER;
  1783. NvAPI_Status status = NvAPI_DRS_EnumSettings( hSession, hProfile, 0, &numSetRead, setArray );
  1784. if (status != NVAPI_OK)
  1785. {
  1786. PrintError( status, 0x454e4d53, numOfSettings );
  1787. return;
  1788. }
  1789. for( unsigned int i = 0; i < numSetRead; i++ )
  1790. {
  1791. if ( setArray[ i ].settingLocation != NVDRS_CURRENT_PROFILE_LOCATION )
  1792. {
  1793. continue;
  1794. }
  1795. wcstombs_s( &nChars, szTemp, 2048, (wchar_t*)(setArray[ i ].settingName), 2048 );
  1796. Msg( "Setting Name: %s\n", szTemp );
  1797. Msg( "Setting ID: %X\n", setArray[ i ].settingId );
  1798. Msg( "Setting Type: %X\n", setArray[ i ].settingType );
  1799. Msg( "Predefined? : %d\n", setArray[ i ].isCurrentPredefined );
  1800. switch ( setArray[ i ].settingType )
  1801. {
  1802. case NVDRS_DWORD_TYPE:
  1803. Msg( "Setting Value: %X\n\n", setArray[ i ].u32CurrentValue );
  1804. break;
  1805. case NVDRS_BINARY_TYPE:
  1806. {
  1807. Msg( "Setting Binary (length=%d) :", setArray[ i ].binaryCurrentValue.valueLength );
  1808. for( unsigned int len = 0; len < setArray[ i ].binaryCurrentValue.valueLength; len++ )
  1809. {
  1810. Msg(" %02x", setArray[ i ].binaryCurrentValue.valueData[ len ] );
  1811. }
  1812. Msg( "\n\n" );
  1813. }
  1814. break;
  1815. case NVDRS_WSTRING_TYPE:
  1816. {
  1817. wcstombs_s( &nChars, szTemp, 2048, ( wchar_t* )( setArray[ i ].wszCurrentValue ), 2048 );
  1818. Msg( "Setting Value: %s\n\n", szTemp );
  1819. }
  1820. break;
  1821. }
  1822. }
  1823. }
  1824. Msg("\n");
  1825. }
  1826. #endif
  1827. void ForceProfileSettings( NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, int numOfSettings )
  1828. {
  1829. bool bNeedsSaving = false;
  1830. uint32 unFirstFixedProp = 0;
  1831. uint32 unFirstFixedValue = 0;
  1832. if ( numOfSettings > 0 )
  1833. {
  1834. NVDRS_SETTING *setArray = new NVDRS_SETTING[ numOfSettings ];
  1835. V_memset( setArray, 0, sizeof( NVDRS_SETTING ) * numOfSettings );
  1836. NvU32 numSetRead = numOfSettings;
  1837. setArray[ 0 ].version = NVDRS_SETTING_VER;
  1838. NvAPI_Status status = NvAPI_DRS_EnumSettings( hSession, hProfile, 0, &numSetRead, setArray );
  1839. if ( status != NVAPI_OK )
  1840. {
  1841. // PrintError( status, 0x454e4d53, numOfSettings );
  1842. return;
  1843. }
  1844. for ( unsigned int i = 0; i < numSetRead; i++ )
  1845. {
  1846. if ( setArray[ i ].settingLocation != NVDRS_CURRENT_PROFILE_LOCATION )
  1847. {
  1848. continue;
  1849. }
  1850. bool bNeedsReset = false;
  1851. switch ( setArray[ i ].settingId )
  1852. {
  1853. case 0x002C7F45: // Ambient Occlusion Compatibility
  1854. switch ( setArray[ i ].u32CurrentValue )
  1855. {
  1856. case 0: // disabled
  1857. case 0x2C: // CS:GO
  1858. break;
  1859. default:
  1860. bNeedsReset = true;
  1861. break;
  1862. }
  1863. break;
  1864. case 0x00664339: // NVIDIA Predefined Ambient Occlusion Usage
  1865. switch ( setArray[ i ].u32CurrentValue )
  1866. {
  1867. case 1: // Enabled
  1868. break;
  1869. default:
  1870. bNeedsReset = true;
  1871. break;
  1872. }
  1873. break;
  1874. case 0x00667329: // Ambient Occlusion Setting
  1875. switch ( setArray[ i ].u32CurrentValue )
  1876. {
  1877. case 0: // Off
  1878. break;
  1879. default:
  1880. bNeedsReset = true;
  1881. break;
  1882. }
  1883. break;
  1884. case 0x00738E8F: // texture filtering LOD bias (DX)
  1885. case 0x20403F79: // texture filtering LOD bias (GL)
  1886. switch ( setArray[ i ].u32CurrentValue )
  1887. {
  1888. case 0: // Off
  1889. break;
  1890. default:
  1891. bNeedsReset = true;
  1892. break;
  1893. }
  1894. break;
  1895. }
  1896. if ( bNeedsReset )
  1897. {
  1898. #ifdef _DEBUG
  1899. Msg( "NVIDIA Setting Override Required -- ID: %X Old Value: %X\n", setArray[ i ].settingId, setArray[ i ].u32CurrentValue );
  1900. #endif
  1901. if ( !bNeedsSaving )
  1902. {
  1903. unFirstFixedProp = setArray[ i ].settingId;
  1904. unFirstFixedValue = setArray[ i ].u32CurrentValue;
  1905. }
  1906. status = NvAPI_DRS_RestoreProfileDefaultSetting( hSession, hProfile, setArray[ i ].settingId );
  1907. if ( status != NVAPI_OK )
  1908. {
  1909. PrintError( status, setArray[ i ].settingId, setArray[ i ].u32CurrentValue );
  1910. }
  1911. bNeedsSaving = true;
  1912. }
  1913. }
  1914. }
  1915. if ( bNeedsSaving )
  1916. {
  1917. NvAPI_Status status;
  1918. status = NvAPI_DRS_SaveSettings( hSession );
  1919. if ( ( status != NVAPI_OK )
  1920. && ( status != NVAPI_FILE_NOT_FOUND )
  1921. && ( status != NVAPI_ERROR ) )
  1922. {
  1923. PrintError( status, unFirstFixedProp, unFirstFixedValue, true );
  1924. }
  1925. }
  1926. }
  1927. bool CheckAndFixProfileSettings( NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, bool &bCSGOProfileFound )
  1928. {
  1929. NvAPI_Status status;
  1930. NVDRS_PROFILE profileInformation = { 0 };
  1931. profileInformation.version = NVDRS_PROFILE_VER;
  1932. status = NvAPI_DRS_GetProfileInfo( hSession, hProfile, &profileInformation );
  1933. if ( status != NVAPI_OK )
  1934. {
  1935. // PrintError( status, 0x50524f46, status );
  1936. return false;
  1937. }
  1938. char szTemp[ 2048 ];
  1939. size_t nChars = 0;
  1940. if ( profileInformation.numOfApps > 0 )
  1941. {
  1942. #if 1 // use the basic V1 info to work with oldest possible drivers
  1943. NVDRS_APPLICATION_V1 *appArray = new NVDRS_APPLICATION_V1[ profileInformation.numOfApps ];
  1944. appArray[ 0 ].version = NVDRS_APPLICATION_VER_V1;
  1945. #else // most recent version of app info
  1946. NVDRS_APPLICATION *appArray = new NVDRS_APPLICATION[ profileInformation.numOfApps ];
  1947. appArray[ 0 ].version = NVDRS_APPLICATION_VER;
  1948. #endif
  1949. NvU32 numAppsRead = profileInformation.numOfApps;
  1950. status = NvAPI_DRS_EnumApplications( hSession, hProfile, 0, &numAppsRead, reinterpret_cast< NVDRS_APPLICATION * >( appArray ) );
  1951. if ( status != NVAPI_OK )
  1952. {
  1953. // PrintError( status, 0x454e4d41, numAppsRead );
  1954. delete[] appArray;
  1955. return false;
  1956. }
  1957. for( unsigned int i = 0; i < numAppsRead; i++ )
  1958. {
  1959. wcstombs_s( &nChars, szTemp, 2048, ( wchar_t* )( appArray[ i ].appName ), 2048 );
  1960. if ( V_stristr( szTemp, "csgo.exe" ) != NULL )
  1961. {
  1962. bCSGOProfileFound = true;
  1963. #ifdef DEBUG
  1964. wcstombs_s( &nChars, szTemp, 2048, ( wchar_t* )( profileInformation.profileName ), 2048 );
  1965. Msg( "Profile Name: %s\n", szTemp );
  1966. Msg( "Number of Applications associated with the Profile: %d\n", profileInformation.numOfApps );
  1967. Msg( "Number of Settings associated with the Profile: %d\n", profileInformation.numOfSettings );
  1968. Msg( "Is Predefined: %d\n\n", profileInformation.isPredefined );
  1969. Msg( "Executable: %s\n", szTemp);
  1970. wcstombs_s( &nChars, szTemp, 2048, ( wchar_t* )( appArray[ i ].userFriendlyName ), 2048 );
  1971. Msg( "User Friendly Name: %s\n", szTemp );
  1972. Msg( "Is Predefined: %d\n\n", appArray[ i ].isPredefined );
  1973. DumpProfileSettings( hSession, hProfile, profileInformation.numOfSettings );
  1974. #endif
  1975. ForceProfileSettings( hSession, hProfile, profileInformation.numOfSettings );
  1976. }
  1977. }
  1978. delete[] appArray;
  1979. }
  1980. return true;
  1981. }
  1982. void ScanAndFixNvDriverProfiles()
  1983. {
  1984. NvAPI_Status status;
  1985. status = NvAPI_Initialize();
  1986. if ( status != NVAPI_OK )
  1987. {
  1988. // will get here for any non-Nv drivers or really really old Nv drivers that don't support NvAPI
  1989. return;
  1990. }
  1991. NvDRSSessionHandle hSession = 0;
  1992. status = NvAPI_DRS_CreateSession( &hSession );
  1993. if ( status == NVAPI_OK )
  1994. {
  1995. status = NvAPI_DRS_LoadSettings( hSession );
  1996. if ( status == NVAPI_OK )
  1997. {
  1998. NvDRSProfileHandle hProfile = 0;
  1999. bool bCSGOProfileFound = false;
  2000. unsigned int index = 0;
  2001. while ( ( status = NvAPI_DRS_EnumProfiles( hSession, index, &hProfile ) ) == NVAPI_OK )
  2002. {
  2003. CheckAndFixProfileSettings( hSession, hProfile, bCSGOProfileFound );
  2004. index++;
  2005. }
  2006. // force global settings
  2007. status = NvAPI_DRS_GetBaseProfile( hSession, &hProfile );
  2008. if ( status == NVAPI_OK )
  2009. {
  2010. NVDRS_PROFILE profileInformation = { 0 };
  2011. profileInformation.version = NVDRS_PROFILE_VER;
  2012. status = NvAPI_DRS_GetProfileInfo( hSession, hProfile, &profileInformation );
  2013. if ( status == NVAPI_OK )
  2014. {
  2015. ForceProfileSettings( hSession, hProfile, profileInformation.numOfSettings );
  2016. }
  2017. }
  2018. }
  2019. }
  2020. NvAPI_DRS_DestroySession( hSession );
  2021. hSession = 0;
  2022. }
  2023. #endif
  2024. //-----------------------------------------------------------------------------
  2025. // Constructor, destructor
  2026. //-----------------------------------------------------------------------------
  2027. CShaderAPIDx8::CShaderAPIDx8() :
  2028. m_Textures( 32 ),
  2029. m_CurrStack( -1 ),
  2030. m_pRenderMesh( 0 ),
  2031. m_nDynamicVBSize( DYNAMIC_VERTEX_BUFFER_MEMORY ),
  2032. m_pMaterial( NULL ),
  2033. m_CurrentFrame( 0 ),
  2034. m_InSelectionMode( false ),
  2035. m_SelectionMinZ( FLT_MAX ),
  2036. m_SelectionMaxZ( FLT_MIN ),
  2037. m_pSelectionBuffer( 0 ),
  2038. m_pSelectionBufferEnd( 0 ),
  2039. m_bResetRenderStateNeeded( false ),
  2040. m_nPixFrame(0),
  2041. m_bPixCapturing(false),
  2042. m_nPIXErrorCount(0),
  2043. m_pBackBufferSurfaces(),
  2044. m_pBackBufferSurfaceSRGB( 0 ),
  2045. m_pZBufferSurface( 0 ),
  2046. m_bResettingRenderState( false ),
  2047. m_bReadPixelsEnabled( false ),
  2048. m_bSinglePassFlashlightMode( false ),
  2049. m_ToneMappingScale( 1.0f, 1.0f, 1.0f, 1.0f ),
  2050. m_hFullScreenTexture( INVALID_SHADERAPI_TEXTURE_HANDLE ),
  2051. m_hLinearToGammaTableTexture( INVALID_SHADERAPI_TEXTURE_HANDLE ),
  2052. m_hLinearToGammaTableIdentityTexture( INVALID_SHADERAPI_TEXTURE_HANDLE ),
  2053. m_fShadowSlopeScaleDepthBias( 16.0f ),
  2054. m_fShadowDepthBias( 0.00008f ),
  2055. m_hCachedRenderTarget( INVALID_SHADERAPI_TEXTURE_HANDLE ),
  2056. m_bUsingSRGBRenderTarget( false ),
  2057. m_bFlipCulling( false ),
  2058. m_flCurrGameTime( 0.0f ),
  2059. #if defined( _X360 )
  2060. m_XboxFontMemoryDict( k_eDictCompareTypeCaseInsensitive ),
  2061. #endif
  2062. m_bIsStereoActiveThisFrame( false )
  2063. {
  2064. // FIXME: Remove! Backward compat
  2065. m_bAdapterSet = false;
  2066. m_bBuffer2FramesAhead = false;
  2067. m_bReadPixelsEnabled = true;
  2068. memset( m_pMatrixStack, 0, sizeof(ID3DXMatrixStack*) * NUM_MATRIX_MODES );
  2069. memset( &m_DynamicState, 0, sizeof(m_DynamicState) );
  2070. //m_DynamicState.m_HeightClipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE;
  2071. m_nWindowHeight = m_nWindowWidth = 0;
  2072. m_maxBoneLoaded = 0;
  2073. m_bEnableDebugTextureList = 0;
  2074. m_bDebugTexturesRendering = 0;
  2075. m_pDebugTextureList = NULL;
  2076. m_nTextureMemoryUsedLastFrame = 0;
  2077. m_nTextureMemoryUsedTotal = 0;
  2078. m_nTextureMemoryUsedPicMip1 = 0;
  2079. m_nTextureMemoryUsedPicMip2 = 0;
  2080. m_nDebugDataExportFrame = 0;
  2081. m_SceneFogColor[0] = 0;
  2082. m_SceneFogColor[1] = 0;
  2083. m_SceneFogColor[2] = 0;
  2084. m_SceneFogMode = MATERIAL_FOG_NONE;
  2085. // We haven't yet detected whether we support CreateQuery or not yet.
  2086. memset(IntRenderingParameters,0,sizeof(IntRenderingParameters));
  2087. memset(FloatRenderingParameters,0,sizeof(FloatRenderingParameters));
  2088. memset(VectorRenderingParameters,0,sizeof(VectorRenderingParameters));
  2089. m_pDeformationStackPtr = m_DeformationStack + DEFORMATION_STACK_DEPTH;
  2090. m_bGPUOwned = false;
  2091. m_MaxVectorVertexShaderConstant = 0;
  2092. m_MaxBooleanVertexShaderConstant = 0;
  2093. m_MaxIntegerVertexShaderConstant = 0;
  2094. m_MaxVectorPixelShaderConstant = 0;
  2095. m_MaxBooleanPixelShaderConstant = 0;
  2096. m_MaxIntegerPixelShaderConstant = 0;
  2097. // init to cover "real" backbuffer and HDR backbuffer
  2098. m_pBackBufferSurfaces.SetCount( 2 );
  2099. m_pBackBufferSurfaces[0] = NULL;
  2100. m_pBackBufferSurfaces[1] = NULL;
  2101. ClearStdTextureHandles();
  2102. V_memset( &m_CascadedShadowMappingState, 0, sizeof( m_CascadedShadowMappingState ) );
  2103. V_memset( &m_CascadedShadowMappingState_LightMapScaled, 0, sizeof( m_CascadedShadowMappingState_LightMapScaled ) );
  2104. m_pCascadedShadowMappingDepthTexture = NULL;
  2105. #ifdef _GAMECONSOLE
  2106. m_bInZPass = false;
  2107. m_nZPassCounter = 0;
  2108. m_zPassSnapshot = -1;
  2109. #endif
  2110. #if defined( _PS3 ) || defined( _OSX )
  2111. g_pShaderAPI = this;
  2112. g_pShaderDevice = this;
  2113. #endif
  2114. #ifdef _PS3
  2115. //
  2116. // Set artificial texture handle (BACKBUFFER)
  2117. //
  2118. {
  2119. ShaderAPITextureHandle_t hTexture = m_Textures.AddToTail();
  2120. m_ArtificialTextureHandles.AddToTail( hTexture );
  2121. Texture_t *pTexture = &m_Textures[hTexture];
  2122. void Ps3gcmInitializeArtificialTexture( Texture_t *pTexture );
  2123. Ps3gcmInitializeArtificialTexture( pTexture );
  2124. pTexture->m_DebugName = "^PS3^BACKBUFFER";
  2125. pTexture->SetImageFormat( IMAGE_FORMAT_ARGB8888 );
  2126. }
  2127. //
  2128. // Set artificial texture handle (DEPTHBUFFER)
  2129. //
  2130. {
  2131. ShaderAPITextureHandle_t hTexture = m_Textures.AddToTail();
  2132. m_ArtificialTextureHandles.AddToTail( hTexture );
  2133. Texture_t *pTexture = &m_Textures[hTexture];
  2134. void Ps3gcmInitializeArtificialTexture( Texture_t *pTexture );
  2135. Ps3gcmInitializeArtificialTexture( pTexture );
  2136. pTexture->m_DebugName = "^PS3^DEPTHBUFFER";
  2137. pTexture->SetImageFormat( IMAGE_FORMAT_D24S8 );
  2138. }
  2139. //
  2140. // End of artificial texture handles
  2141. //
  2142. #endif
  2143. m_bGeneratingCSMs = false;
  2144. m_bVtxLitMesh = false;
  2145. m_bLmapMesh = false;
  2146. m_bUnlitMesh = false;
  2147. #ifdef WIN32
  2148. ScanAndFixNvDriverProfiles();
  2149. m_pNVAPI_registeredDepthStencilSurface = NULL;
  2150. m_pNVAPI_registeredDepthTexture = NULL;
  2151. #endif
  2152. }
  2153. #ifdef _PS3
  2154. void Ps3gcmInitializeArtificialTexture( Texture_t *pTexture )
  2155. {
  2156. pTexture->m_DebugName = "^PS3^";
  2157. pTexture->m_Flags = Texture_t::IS_ALLOCATED;
  2158. pTexture->m_Depth = 1;
  2159. pTexture->m_Count = 1;
  2160. pTexture->m_CountIndex = 0;
  2161. pTexture->m_CreationFlags = 0;
  2162. pTexture->m_Flags |= 0;
  2163. // Set the initial texture state
  2164. pTexture->m_NumCopies = 1;
  2165. pTexture->m_CurrentCopy = 0;
  2166. // -- patched after surfaces are created --
  2167. pTexture->m_Width = 1;
  2168. pTexture->m_Height = 1;
  2169. pTexture->SetTexture( NULL );
  2170. // --
  2171. pTexture->SetImageFormat( IMAGE_FORMAT_ARGB8888 );
  2172. pTexture->m_UTexWrap = D3DTADDRESS_CLAMP;
  2173. pTexture->m_VTexWrap = D3DTADDRESS_CLAMP;
  2174. pTexture->m_WTexWrap = D3DTADDRESS_CLAMP;
  2175. pTexture->m_MinFilter = pTexture->m_MagFilter = D3DTEXF_LINEAR;
  2176. pTexture->m_NumLevels = 1;
  2177. pTexture->m_MipFilter = D3DTEXF_NONE;
  2178. pTexture->m_SwitchNeeded = false;
  2179. pTexture->m_SizeBytes = 0;
  2180. pTexture->m_SizeTexels = 0;
  2181. pTexture->m_LastBoundFrame = -1;
  2182. }
  2183. ShaderAPITextureHandle_t Ps3gcmGetArtificialTextureHandle( int iHandle )
  2184. {
  2185. return ( ( CShaderAPIDx8 * ) g_pShaderAPIDX8 )->m_ArtificialTextureHandles[ iHandle ];
  2186. }
  2187. void Ps3gcmInitializeArtificialTexture( int iHandle, IDirect3DBaseTexture *pPtr )
  2188. {
  2189. Texture_t *pTexture = &( ( CShaderAPIDx8 * ) g_pShaderAPIDX8 )->GetTexture( Ps3gcmGetArtificialTextureHandle( iHandle ) );
  2190. pTexture->SetTexture( pPtr );
  2191. D3DSURFACE_DESC ddd;
  2192. pPtr->GetLevelDesc( 0, &ddd );
  2193. pTexture->m_Width = ddd.Width;
  2194. pTexture->m_Height = ddd.Height;
  2195. }
  2196. #endif
  2197. CShaderAPIDx8::~CShaderAPIDx8()
  2198. {
  2199. if ( m_DynamicState.m_pVectorVertexShaderConstant )
  2200. {
  2201. delete[] m_DynamicState.m_pVectorVertexShaderConstant;
  2202. m_DynamicState.m_pVectorVertexShaderConstant = NULL;
  2203. }
  2204. if ( m_DynamicState.m_pBooleanVertexShaderConstant )
  2205. {
  2206. delete[] m_DynamicState.m_pBooleanVertexShaderConstant;
  2207. m_DynamicState.m_pBooleanVertexShaderConstant = NULL;
  2208. }
  2209. if ( m_DynamicState.m_pIntegerVertexShaderConstant )
  2210. {
  2211. delete[] m_DynamicState.m_pIntegerVertexShaderConstant;
  2212. m_DynamicState.m_pIntegerVertexShaderConstant = NULL;
  2213. }
  2214. if ( m_DynamicState.m_pVectorPixelShaderConstant )
  2215. {
  2216. delete[] m_DynamicState.m_pVectorPixelShaderConstant;
  2217. m_DynamicState.m_pVectorPixelShaderConstant = NULL;
  2218. }
  2219. if ( m_DynamicState.m_pBooleanPixelShaderConstant )
  2220. {
  2221. delete[] m_DynamicState.m_pBooleanPixelShaderConstant;
  2222. m_DynamicState.m_pBooleanPixelShaderConstant = NULL;
  2223. }
  2224. if ( m_DynamicState.m_pIntegerPixelShaderConstant )
  2225. {
  2226. delete[] m_DynamicState.m_pIntegerPixelShaderConstant;
  2227. m_DynamicState.m_pIntegerPixelShaderConstant = NULL;
  2228. }
  2229. if ( m_pDebugTextureList )
  2230. {
  2231. m_DebugTextureListLock.Lock();
  2232. m_pDebugTextureList->deleteThis();
  2233. m_pDebugTextureList = NULL;
  2234. m_DebugTextureListLock.Unlock();
  2235. }
  2236. }
  2237. void CShaderAPIDx8::ClearStdTextureHandles( void )
  2238. {
  2239. for(int i = 0 ; i < ARRAYSIZE( m_StdTextureHandles ) ; i++ )
  2240. m_StdTextureHandles[i] = INVALID_SHADERAPI_TEXTURE_HANDLE;
  2241. }
  2242. //-----------------------------------------------------------------------------
  2243. // FIXME: Remove! Backward compat.
  2244. //-----------------------------------------------------------------------------
  2245. bool CShaderAPIDx8::OnAdapterSet()
  2246. {
  2247. if ( !DetermineHardwareCaps( ) )
  2248. return false;
  2249. // FIXME: Check g_pHardwareConfig->ActualCaps() for a preferred DX level
  2250. OverrideCaps( 0 );
  2251. m_bAdapterSet = true;
  2252. return true;
  2253. }
  2254. //-----------------------------------------------------------------------------
  2255. // Can we download textures?
  2256. //-----------------------------------------------------------------------------
  2257. bool CShaderAPIDx8::CanDownloadTextures() const
  2258. {
  2259. if ( IsDeactivated() )
  2260. return false;
  2261. return IsActive();
  2262. }
  2263. //-----------------------------------------------------------------------------
  2264. // Grab the render targets
  2265. //-----------------------------------------------------------------------------
  2266. void CShaderAPIDx8::AcquireInternalRenderTargets()
  2267. {
  2268. if ( mat_debugalttab.GetBool() )
  2269. {
  2270. Warning( "mat_debugalttab: CShaderAPIDx8::AcquireInternalRenderTargets\n" );
  2271. }
  2272. Assert( m_pBackBufferSurfaces.Count() > BACK_BUFFER_INDEX_DEFAULT );
  2273. if ( m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT] == NULL )
  2274. {
  2275. Dx9Device()->GetRenderTarget( 0, &m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT] );
  2276. Assert( m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT] );
  2277. }
  2278. Assert( m_pBackBufferSurfaces.Count() > BACK_BUFFER_INDEX_HDR );
  2279. if( ( g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) &&
  2280. ( m_pBackBufferSurfaces[BACK_BUFFER_INDEX_HDR] == NULL ) )
  2281. {
  2282. // create a float16 HDR rendertarget
  2283. int nWidth, nHeight;
  2284. GetBackBufferDimensions( nWidth, nHeight );
  2285. HRESULT hRes = Dx9Device()->CreateRenderTarget(
  2286. nWidth,
  2287. nHeight,
  2288. D3DFMT_A16B16G16R16F,
  2289. m_PresentParameters.MultiSampleType, // TODO: Check if the HW supports this
  2290. m_PresentParameters.MultiSampleQuality,
  2291. false, // Lockable
  2292. &m_pBackBufferSurfaces[BACK_BUFFER_INDEX_HDR],
  2293. NULL );
  2294. if ( ( hRes != D3D_OK ) || m_pBackBufferSurfaces[BACK_BUFFER_INDEX_HDR] == NULL )
  2295. hRes = Dx9Device()->CreateRenderTarget(
  2296. nWidth,
  2297. nHeight,
  2298. D3DFMT_A16B16G16R16F,
  2299. D3DMULTISAMPLE_NONE,
  2300. 0,
  2301. false, // Lockable
  2302. &m_pBackBufferSurfaces[BACK_BUFFER_INDEX_HDR],
  2303. NULL );
  2304. Assert( ( hRes == D3D_OK ) && m_pBackBufferSurfaces[BACK_BUFFER_INDEX_HDR] );
  2305. }
  2306. #if defined( _X360 )
  2307. if ( !m_pBackBufferSurfaceSRGB )
  2308. {
  2309. // create a SRGB back buffer clone
  2310. int backWidth, backHeight;
  2311. ShaderAPI()->GetBackBufferDimensions( backWidth, backHeight );
  2312. D3DFORMAT backBufferFormat = ImageLoader::ImageFormatToD3DFormat( g_pShaderDevice->GetBackBufferFormat() );
  2313. #if defined( CSTRIKE15 )
  2314. // [mariod] - implicit srgb render targets (regular 8888, writes happen in shaders) as opposed to PWL
  2315. m_pBackBufferSurfaceSRGB = g_TextureHeap.AllocRenderTargetSurface( backWidth, backHeight, backBufferFormat, RT_MULTISAMPLE_MATCH_BACKBUFFER, 0 );
  2316. #else
  2317. m_pBackBufferSurfaceSRGB = g_TextureHeap.AllocRenderTargetSurface( backWidth, backHeight, (D3DFORMAT)MAKESRGBFMT( backBufferFormat ), RT_MULTISAMPLE_MATCH_BACKBUFFER, 0 );
  2318. #endif
  2319. }
  2320. #endif
  2321. if ( !m_pZBufferSurface )
  2322. {
  2323. Dx9Device()->GetDepthStencilSurface( &m_pZBufferSurface );
  2324. Assert( m_pZBufferSurface );
  2325. SPEW_REFCOUNT_EXPECTED( m_pZBufferSurface, ==, 2 );
  2326. }
  2327. }
  2328. //-----------------------------------------------------------------------------
  2329. // Release the render targets
  2330. //-----------------------------------------------------------------------------
  2331. void CShaderAPIDx8::ReleaseInternalRenderTargets( )
  2332. {
  2333. if( mat_debugalttab.GetBool() )
  2334. {
  2335. Warning( "mat_debugalttab: CShaderAPIDx8::ReleaseInternalRenderTargets\n" );
  2336. }
  2337. // Note: This function does not release renderable textures created elsewhere
  2338. // Those should be released separately via the texure manager
  2339. FOR_EACH_VEC( m_pBackBufferSurfaces, i )
  2340. {
  2341. if ( m_pBackBufferSurfaces[i] != NULL )
  2342. {
  2343. IDirect3DSurface9* backBufferSurface = m_pBackBufferSurfaces[i];
  2344. m_pBackBufferSurfaces[i] = NULL;
  2345. // Default back buffer may have a reference held by DirectX.
  2346. int nRemainingReferences = backBufferSurface->Release();
  2347. Assert(nRemainingReferences == 0 || i == BACK_BUFFER_INDEX_DEFAULT && nRemainingReferences <= 1);
  2348. }
  2349. }
  2350. if ( m_pZBufferSurface )
  2351. {
  2352. #if defined(_WIN32) && !defined( DX_TO_GL_ABSTRACTION )
  2353. if ( m_pNVAPI_registeredDepthStencilSurface != NULL )
  2354. {
  2355. // Unregister old one if there is any
  2356. SPEW_REFCOUNT( m_pNVAPI_registeredDepthStencilSurface );
  2357. NvAPI_D3D9_UnregisterResource( m_pNVAPI_registeredDepthStencilSurface );
  2358. SPEW_REFCOUNT( m_pNVAPI_registeredDepthStencilSurface );
  2359. m_pNVAPI_registeredDepthStencilSurface = NULL;
  2360. }
  2361. if ( m_pNVAPI_registeredDepthTexture != NULL )
  2362. {
  2363. // Unregister old one if there is any
  2364. SPEW_REFCOUNT( m_pNVAPI_registeredDepthTexture );
  2365. NvAPI_D3D9_UnregisterResource( m_pNVAPI_registeredDepthTexture );
  2366. SPEW_REFCOUNT( m_pNVAPI_registeredDepthTexture );
  2367. m_pNVAPI_registeredDepthTexture = NULL;
  2368. }
  2369. #endif
  2370. SPEW_REFCOUNT_EXPECTED( m_pZBufferSurface, <=, 2 );
  2371. m_pZBufferSurface->Release();
  2372. m_pZBufferSurface = NULL;
  2373. }
  2374. }
  2375. //-----------------------------------------------------------------------------
  2376. // During init, places the persisted texture back into the back buffer.
  2377. // The initial 360 fixup present will then not flash. This routine has to be
  2378. // self contained, no other shader api systems are viable during init.
  2379. //-----------------------------------------------------------------------------
  2380. bool CShaderAPIDx8::RestorePersistedDisplay( bool bUseFrontBuffer )
  2381. {
  2382. #if defined( _X360 )
  2383. if ( !( XboxLaunch()->GetLaunchFlags() & LF_INTERNALLAUNCH ) )
  2384. {
  2385. // there is no persisted screen
  2386. return false;
  2387. }
  2388. OwnGPUResources( false );
  2389. // HLSL source for the persist shader:
  2390. const char *strVertexShaderProgram =
  2391. " float4x4 matWVP : register(c0);"
  2392. " struct VS_IN"
  2393. " {"
  2394. " float4 ObjPos : POSITION;"
  2395. " float2 TexCoord : TEXCOORD;"
  2396. " };"
  2397. " struct VS_OUT"
  2398. " {"
  2399. " float4 ProjPos : POSITION;"
  2400. " float2 TexCoord : TEXCOORD;"
  2401. " };"
  2402. " VS_OUT main( VS_IN In )"
  2403. " {"
  2404. " VS_OUT Out; "
  2405. " Out.ProjPos = mul( matWVP, In.ObjPos );"
  2406. " Out.TexCoord = In.TexCoord;"
  2407. " return Out;"
  2408. " }";
  2409. const char *strPixelShaderProgram =
  2410. " struct PS_IN"
  2411. " {"
  2412. " float2 TexCoord : TEXCOORD;"
  2413. " };"
  2414. " sampler detail : register( s0 );"
  2415. " float4 main( PS_IN In ) : COLOR"
  2416. " {"
  2417. " return tex2D( detail, In.TexCoord );"
  2418. " }";
  2419. // Hard-coded compiled shader data, so we don't have to bloat our DLLs
  2420. // with all the shader compilation stuff from the D3D libs (over 2 MB!)
  2421. #if defined( _X360 ) && ( _XDK_VER != 20764 )
  2422. // Make sure this hard-coded shader data gets updated with each XDK rev
  2423. #if !defined( JUNE_2009_XDK_ISSUES )
  2424. #error "Define X360_LINK_WITH_SHADER_COMPILE temporarily (to verify shader data and spew out new data if necessary)"
  2425. #endif
  2426. #endif
  2427. // As of L4D ship, 80 DWORDS
  2428. DWORD vertexShaderData[] = {
  2429. 0x102a1101, 0x000000bc, 0x00000084, 0x00000000, 0x00000024, 0x00000000, 0x00000084, 0x00000000,
  2430. 0x00000000, 0x0000005c, 0x0000001c, 0x0000004f, 0xfffe0300, 0x00000001, 0x0000001c, 0x00000000,
  2431. 0x00000048, 0x00000030, 0x00020000, 0x00040000, 0x00000038, 0x00000000, 0x6d617457, 0x565000ab,
  2432. 0x00030003, 0x00040004, 0x00010000, 0x00000000, 0x76735f33, 0x5f300032, 0x2e302e32, 0x30373634,
  2433. 0x2e3000ab, 0x00000000, 0x00000084, 0x00010002, 0x00000000, 0x00000000, 0x00000821, 0x00000001,
  2434. 0x00000002, 0x00000001, 0x00000290, 0x00100003, 0x00305004, 0x00003050, 0x00001009, 0x30052003,
  2435. 0x00001200, 0xc2000000, 0x00004005, 0x00001200, 0xc4000000, 0x00001009, 0x00002200, 0x00000000,
  2436. 0x05f82000, 0x00000688, 0x00000000, 0x05f80000, 0x00000fc8, 0x00000000, 0xc80f0001, 0x001b8800,
  2437. 0xa1020300, 0xc80f0001, 0x00c68800, 0xab020201, 0xc80f0001, 0x00b13494, 0xab020101, 0xc80f803e,
  2438. 0x006c0034, 0xab020001, 0xc8038000, 0x00b0b000, 0xe2000000, 0x00000000, 0x00000000, 0x00000000,
  2439. };
  2440. // As of L4D ship, 57 DWORDS
  2441. DWORD pixelShaderData1[] = {
  2442. 0x102a1100, 0x000000a8, 0x0000003c, 0x00000000, 0x00000024, 0x00000000, 0x00000084, 0x00000000,
  2443. 0x00000000, 0x0000005c, 0x0000001c, 0x0000004f, 0xffff0300, 0x00000001, 0x0000001c, 0x00000000,
  2444. 0x00000048, 0x00000030, 0x00030000, 0x00010000, 0x00000038, 0x00000000, 0x64657461, 0x696c00ab,
  2445. 0x0004000c, 0x00010001, 0x00010000, 0x00000000, 0x70735f33, 0x5f300032, 0x2e302e32, 0x30373634,
  2446. 0x2e3000ab, 0x00000000, 0x0000003c, 0x10000000, 0x00000004, 0x00000000, 0x00000821, 0x00010001,
  2447. 0x00000001, 0x00003050, 0x00011002, 0x00001200, 0xc4000000, 0x00001003, 0x00002200, 0x00000000,
  2448. 0x10080001, 0x1f1ff688, 0x00004000, 0xc80f8000, 0x00000000, 0xe2000000, 0x00000000, 0x00000000,
  2449. 0x00000000,
  2450. };
  2451. D3DVERTEXELEMENT9 VertexElements[3] =
  2452. {
  2453. { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  2454. { 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
  2455. D3DDECL_END()
  2456. };
  2457. IDirect3DTexture *pTexture;
  2458. if ( bUseFrontBuffer )
  2459. {
  2460. Dx9Device()->GetFrontBuffer( &pTexture );
  2461. }
  2462. else
  2463. {
  2464. // 360 holds a persistent image across restarts
  2465. Dx9Device()->GetPersistedTexture( &pTexture );
  2466. }
  2467. // Build the shaders to do this rendering (fixed-function pipeline FTW :o/ )
  2468. IDirect3DVertexShader9 *pVertexShader;
  2469. if ( !BuildStaticShader( true, (void **)&pVertexShader, "vertex shader",
  2470. strVertexShaderProgram, vertexShaderData, sizeof( vertexShaderData ) ) )
  2471. return false;
  2472. IDirect3DPixelShader9 *pPixelShader;
  2473. if ( !BuildStaticShader( false, (void **)&pPixelShader, "pixel shader",
  2474. strPixelShaderProgram, pixelShaderData1, sizeof( pixelShaderData1 ) ) )
  2475. return false;
  2476. int w, h;
  2477. GetBackBufferDimensions( w, h );
  2478. // Create a vertex declaration from the element descriptions.
  2479. IDirect3DVertexDeclaration9 *pVertexDecl;
  2480. Dx9Device()->CreateVertexDeclaration( VertexElements, &pVertexDecl );
  2481. XMMATRIX matWVP = XMMatrixOrthographicOffCenterLH( 0, (FLOAT)w, (FLOAT)h, 0, 0, 1 );
  2482. ConVarRef mat_monitorgamma( "mat_monitorgamma" );
  2483. ConVarRef mat_monitorgamma_tv_range_min( "mat_monitorgamma_tv_range_min" );
  2484. ConVarRef mat_monitorgamma_tv_range_max( "mat_monitorgamma_tv_range_max" );
  2485. ConVarRef mat_monitorgamma_tv_exp( "mat_monitorgamma_tv_exp" );
  2486. ConVarRef mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled" );
  2487. g_pShaderDeviceDx8->SetHardwareGammaRamp( mat_monitorgamma.GetFloat(), mat_monitorgamma_tv_range_min.GetFloat(), mat_monitorgamma_tv_range_max.GetFloat(),
  2488. mat_monitorgamma_tv_exp.GetFloat(), mat_monitorgamma_tv_enabled.GetBool() );
  2489. // Structure to hold vertex data.
  2490. struct COLORVERTEX
  2491. {
  2492. FLOAT Position[3];
  2493. float TexCoord[2];
  2494. };
  2495. COLORVERTEX Vertices[4];
  2496. Vertices[0].Position[0] = 0;
  2497. Vertices[0].Position[1] = 0;
  2498. Vertices[0].Position[2] = 0;
  2499. Vertices[0].TexCoord[0] = 0;
  2500. Vertices[0].TexCoord[1] = 0;
  2501. Vertices[1].Position[0] = w-1;
  2502. Vertices[1].Position[1] = 0;
  2503. Vertices[1].Position[2] = 0;
  2504. Vertices[1].TexCoord[0] = 1;
  2505. Vertices[1].TexCoord[1] = 0;
  2506. Vertices[2].Position[0] = w-1;
  2507. Vertices[2].Position[1] = h-1;
  2508. Vertices[2].Position[2] = 0;
  2509. Vertices[2].TexCoord[0] = 1;
  2510. Vertices[2].TexCoord[1] = 1;
  2511. Vertices[3].Position[0] = 0;
  2512. Vertices[3].Position[1] = h-1;
  2513. Vertices[3].Position[2] = 0;
  2514. Vertices[3].TexCoord[0] = 0;
  2515. Vertices[3].TexCoord[1] = 1;
  2516. Dx9Device()->SetTexture( 0, pTexture );
  2517. Dx9Device()->SetVertexShader( pVertexShader );
  2518. Dx9Device()->SetPixelShader( pPixelShader );
  2519. Dx9Device()->SetVertexShaderConstantF( 0, (FLOAT*)&matWVP, 4 );
  2520. Dx9Device()->SetVertexDeclaration( pVertexDecl );
  2521. Dx9Device()->DrawPrimitiveUP( D3DPT_QUADLIST, 1, Vertices, sizeof( COLORVERTEX ) );
  2522. Dx9Device()->SetVertexShader( NULL );
  2523. Dx9Device()->SetPixelShader( NULL );
  2524. Dx9Device()->SetTexture( 0, NULL );
  2525. Dx9Device()->SetVertexDeclaration( NULL );
  2526. pVertexShader->Release();
  2527. pPixelShader->Release();
  2528. pVertexDecl->Release();
  2529. pTexture->Release();
  2530. OwnGPUResources( true );
  2531. return true;
  2532. #else
  2533. return false;
  2534. #endif
  2535. }
  2536. //-----------------------------------------------------------------------------
  2537. // Initialize, shutdown the Device....
  2538. //-----------------------------------------------------------------------------
  2539. bool CShaderAPIDx8::OnDeviceInit()
  2540. {
  2541. AcquireInternalRenderTargets();
  2542. g_pHardwareConfig->CapsForEdit().m_TextureMemorySize = g_pShaderDeviceMgrDx8->GetVidMemBytes( m_nAdapter );
  2543. CreateMatrixStacks();
  2544. // Hide the cursor
  2545. RECORD_COMMAND( DX8_SHOW_CURSOR, 1 );
  2546. RECORD_INT( false );
  2547. #if !defined( _X360 )
  2548. Dx9Device()->ShowCursor( false );
  2549. #endif
  2550. // Initialize the shader manager
  2551. ShaderManager()->Init();
  2552. // Initialize the shader shadow
  2553. ShaderShadow()->Init();
  2554. // Initialize the mesh manager
  2555. MeshMgr()->Init();
  2556. m_bToolsMode = IsPlatformWindows() && ( CommandLine()->CheckParm( "-tools" ) != NULL );
  2557. // Use fat vertices when running in tools
  2558. MeshMgr()->UseFatVertices( m_bToolsMode );
  2559. // Initialize the transition table.
  2560. m_TransitionTable.Init();
  2561. // Initialize the render state
  2562. InitRenderState();
  2563. // Clear the z and color buffers
  2564. ClearBuffers( true, true, true, -1, -1 );
  2565. AllocFrameSyncObjects();
  2566. AllocNonInteractiveRefreshObjects();
  2567. RECORD_COMMAND( DX8_BEGIN_SCENE, 0 );
  2568. // Apply mandatory initialization HW fixups, GPU state will be left as expected
  2569. if ( IsX360() )
  2570. {
  2571. // place the possible persisted display into the back buffer, ready for present()
  2572. RestorePersistedDisplay( false );
  2573. // 360 MUST perform an initial swap to stabilize the state
  2574. // this ensures any states (e.g. gamma) are respected
  2575. // without this, the 360 resets to internal default state on the first swap
  2576. OwnGPUResources( false );
  2577. Dx9Device()->Present( 0, 0, 0, 0 );
  2578. // present corrupts the GPU state and back buffer (according to docs)
  2579. // re-clear the back buffer in order to re-establish the expected contents
  2580. ResetRenderState( false );
  2581. ClearBuffers( true, true, true, -1, -1 );
  2582. // place the front buffer image in the back buffer, later systems will detect and grab
  2583. // other systems will detect and grab
  2584. RestorePersistedDisplay( true );
  2585. #ifdef PLATFORM_X360
  2586. if ( m_PresentParameters.PresentationInterval != D3DPRESENT_INTERVAL_IMMEDIATE )
  2587. {
  2588. // Ensure our custom present immediate threshold is set.
  2589. EnableVSync_360( true );
  2590. }
  2591. #endif
  2592. }
  2593. Dx9Device()->BeginScene();
  2594. return true;
  2595. }
  2596. void CShaderAPIDx8::OnDeviceShutdown()
  2597. {
  2598. if ( IsX360() || !IsActive() )
  2599. return;
  2600. // Deallocate all textures
  2601. DeleteAllTextures();
  2602. // Release render targets
  2603. ReleaseInternalRenderTargets();
  2604. // Free objects that are used for frame syncing.
  2605. FreeFrameSyncObjects();
  2606. FreeNonInteractiveRefreshObjects();
  2607. for (int i = 0; i < NUM_MATRIX_MODES; ++i)
  2608. {
  2609. if (m_pMatrixStack[i])
  2610. {
  2611. int ref = m_pMatrixStack[i]->Release();
  2612. Assert( ref == 0 );
  2613. }
  2614. }
  2615. // Shutdown the transition table.
  2616. m_TransitionTable.Shutdown();
  2617. MeshMgr()->Shutdown();
  2618. ShaderManager()->Shutdown();
  2619. ReleaseAllVertexDecl( );
  2620. }
  2621. //-----------------------------------------------------------------------------
  2622. // Sets the mode...
  2623. //-----------------------------------------------------------------------------
  2624. bool CShaderAPIDx8::SetMode( void* VD3DHWND, int nAdapter, const ShaderDeviceInfo_t &info )
  2625. {
  2626. //
  2627. // FIXME: Note that this entire function is backward compat and will go soon
  2628. //
  2629. bool bRestoreNeeded = false;
  2630. if ( IsActive() )
  2631. {
  2632. ReleaseResources();
  2633. OnDeviceShutdown();
  2634. ShutdownDevice();
  2635. bRestoreNeeded = true;
  2636. }
  2637. LOCK_SHADERAPI();
  2638. Assert( D3D() );
  2639. Assert( nAdapter < g_pShaderDeviceMgr->GetAdapterCount() );
  2640. const HardwareCaps_t& actualCaps = g_pShaderDeviceMgr->GetHardwareCaps( nAdapter );
  2641. ShaderDeviceInfo_t actualInfo = info;
  2642. int nDXLevel = actualInfo.m_nDXLevel ? actualInfo.m_nDXLevel : actualCaps.m_nDXSupportLevel;
  2643. if ( nDXLevel > actualCaps.m_nMaxDXSupportLevel )
  2644. {
  2645. nDXLevel = actualCaps.m_nMaxDXSupportLevel;
  2646. }
  2647. actualInfo.m_nDXLevel = g_pShaderDeviceMgr->GetClosestActualDXLevel( nDXLevel );
  2648. if ( !g_pShaderDeviceMgrDx8->ValidateMode( nAdapter, actualInfo ) )
  2649. return false;
  2650. g_pShaderAPI = this;
  2651. g_pShaderDevice = this;
  2652. g_pShaderShadow = ShaderShadow();
  2653. bool bOk = InitDevice( VD3DHWND, nAdapter, actualInfo );
  2654. if ( !bOk )
  2655. return false;
  2656. if ( !OnDeviceInit() )
  2657. return false;
  2658. if ( bRestoreNeeded && IsPC() )
  2659. {
  2660. ReacquireResources();
  2661. }
  2662. return true;
  2663. }
  2664. //-----------------------------------------------------------------------------
  2665. // Creates the matrix stack
  2666. //-----------------------------------------------------------------------------
  2667. void CShaderAPIDx8::CreateMatrixStacks()
  2668. {
  2669. MEM_ALLOC_D3D_CREDIT();
  2670. for (int i = 0; i < NUM_MATRIX_MODES; ++i)
  2671. {
  2672. HRESULT hr = D3DXCreateMatrixStack( 0, &m_pMatrixStack[i] );
  2673. Assert( hr == D3D_OK );
  2674. }
  2675. }
  2676. // Use this when recording *.rec files that need to be run on more than one kind of
  2677. // hardware, etc.
  2678. //#define DX8_COMPATABILITY_MODE
  2679. //-----------------------------------------------------------------------------
  2680. // Vendor-dependent code to turn on alpha to coverage
  2681. //-----------------------------------------------------------------------------
  2682. void CShaderAPIDx8::EnableAlphaToCoverage( void )
  2683. {
  2684. if( !g_pHardwareConfig->ActualCaps().m_bSupportsAlphaToCoverage || !IsAAEnabled() )
  2685. return;
  2686. if ( IsPC() && ( m_PresentParameters.MultiSampleType < D3DMULTISAMPLE_4_SAMPLES ) )
  2687. return;
  2688. D3DRENDERSTATETYPE renderState = (D3DRENDERSTATETYPE)g_pHardwareConfig->Caps().m_AlphaToCoverageState;
  2689. SetRenderState( renderState, g_pHardwareConfig->Caps().m_AlphaToCoverageEnableValue ); // Vendor dependent state
  2690. }
  2691. //-----------------------------------------------------------------------------
  2692. // Vendor-dependent code to turn off alpha to coverage
  2693. //-----------------------------------------------------------------------------
  2694. void CShaderAPIDx8::DisableAlphaToCoverage()
  2695. {
  2696. if( !g_pHardwareConfig->ActualCaps().m_bSupportsAlphaToCoverage || !IsAAEnabled() )
  2697. return;
  2698. if ( IsPC() && ( m_PresentParameters.MultiSampleType < D3DMULTISAMPLE_4_SAMPLES ) )
  2699. return;
  2700. D3DRENDERSTATETYPE renderState = (D3DRENDERSTATETYPE)g_pHardwareConfig->Caps().m_AlphaToCoverageState;
  2701. SetRenderState( renderState, g_pHardwareConfig->Caps().m_AlphaToCoverageDisableValue ); // Vendor dependent state
  2702. }
  2703. //-----------------------------------------------------------------------------
  2704. // Determine capabilities
  2705. //-----------------------------------------------------------------------------
  2706. bool CShaderAPIDx8::DetermineHardwareCaps( )
  2707. {
  2708. HardwareCaps_t& actualCaps = g_pHardwareConfig->ActualCapsForEdit();
  2709. if ( !g_pShaderDeviceMgrDx8->ComputeCapsFromD3D( &actualCaps, m_DisplayAdapter ) )
  2710. return false;
  2711. // See if the file tells us otherwise
  2712. g_pShaderDeviceMgrDx8->ReadDXSupportLevels( actualCaps );
  2713. // Read dxsupport.cfg which has config overrides for particular cards.
  2714. g_pShaderDeviceMgrDx8->ReadHardwareCaps( actualCaps, actualCaps.m_nMaxDXSupportLevel );
  2715. // What's in "-shader" overrides dxsupport.cfg
  2716. const char *pShaderParam = CommandLine()->ParmValue( "-shader" );
  2717. if ( pShaderParam )
  2718. {
  2719. Q_strncpy( actualCaps.m_pShaderDLL, pShaderParam, sizeof( actualCaps.m_pShaderDLL ) );
  2720. }
  2721. return true;
  2722. }
  2723. //-----------------------------------------------------------------------------
  2724. // Override caps based on a particular dx level
  2725. //-----------------------------------------------------------------------------
  2726. void CShaderAPIDx8::OverrideCaps( int nForcedDXLevel )
  2727. {
  2728. // Just use the actual caps if we can't use what was requested or if the default is requested
  2729. if ( nForcedDXLevel <= 0 )
  2730. {
  2731. nForcedDXLevel = g_pHardwareConfig->ActualCaps().m_nDXSupportLevel;
  2732. }
  2733. nForcedDXLevel = g_pShaderDeviceMgr->GetClosestActualDXLevel( nForcedDXLevel );
  2734. g_pHardwareConfig->SetupHardwareCaps( nForcedDXLevel, g_pHardwareConfig->ActualCaps() );
  2735. }
  2736. //-----------------------------------------------------------------------------
  2737. // Called when the dx support level has changed
  2738. //-----------------------------------------------------------------------------
  2739. void CShaderAPIDx8::DXSupportLevelChanged( int nDXLevel )
  2740. {
  2741. LOCK_SHADERAPI();
  2742. if ( IsPC() )
  2743. {
  2744. OverrideCaps( nDXLevel );
  2745. }
  2746. else
  2747. {
  2748. Assert( 0 );
  2749. }
  2750. }
  2751. //-----------------------------------------------------------------------------
  2752. // FIXME: Remove! Backward compat only
  2753. //-----------------------------------------------------------------------------
  2754. int CShaderAPIDx8::GetActualSamplerCount() const
  2755. {
  2756. return g_pHardwareConfig->GetActualSamplerCount();
  2757. }
  2758. int CShaderAPIDx8::StencilBufferBits() const
  2759. {
  2760. return m_bUsingStencil ? m_iStencilBufferBits : 0;
  2761. }
  2762. bool CShaderAPIDx8::IsAAEnabled() const
  2763. {
  2764. bool bAntialiasing = ( m_PresentParameters.MultiSampleType != D3DMULTISAMPLE_NONE );
  2765. return bAntialiasing;
  2766. }
  2767. //-----------------------------------------------------------------------------
  2768. // Methods related to queuing functions to be called per-(pMesh->Draw call) or per-pass
  2769. //-----------------------------------------------------------------------------
  2770. bool CShaderAPIDx8::IsCommitFuncInUse( CommitFuncType_t func, int nFunc ) const
  2771. {
  2772. Assert( nFunc < COMMIT_FUNC_COUNT );
  2773. return ( m_pCommitFlags[func][ nFunc >> 3 ] & ( 1 << ( nFunc & 0x7 ) ) ) != 0;
  2774. }
  2775. void CShaderAPIDx8::MarkCommitFuncInUse( CommitFuncType_t func, int nFunc )
  2776. {
  2777. m_pCommitFlags[func][ nFunc >> 3 ] |= 1 << ( nFunc & 0x7 );
  2778. }
  2779. void CShaderAPIDx8::AddCommitFunc( CommitFuncType_t func, StateCommitFunc_t f )
  2780. {
  2781. m_CommitFuncs[func].AddToTail( f );
  2782. }
  2783. //-----------------------------------------------------------------------------
  2784. // Clears all commit functions
  2785. //-----------------------------------------------------------------------------
  2786. void CShaderAPIDx8::ClearAllCommitFuncs( CommitFuncType_t func )
  2787. {
  2788. memset( m_pCommitFlags[func], 0, COMMIT_FUNC_BYTE_COUNT );
  2789. m_CommitFuncs[func].RemoveAll();
  2790. }
  2791. //-----------------------------------------------------------------------------
  2792. // Calls all commit functions in a particular list
  2793. //-----------------------------------------------------------------------------
  2794. void CShaderAPIDx8::CallCommitFuncs( CommitFuncType_t func, bool bForce )
  2795. {
  2796. // Don't bother committing anything if we're deactivated
  2797. if ( IsDeactivated() )
  2798. return;
  2799. CUtlVector< StateCommitFunc_t > &funcList = m_CommitFuncs[func];
  2800. int nCount = funcList.Count();
  2801. if ( nCount == 0 )
  2802. return;
  2803. for ( int i = 0; i < nCount; ++i )
  2804. {
  2805. funcList[i]( Dx9Device(), m_DesiredState, m_DynamicState, bForce );
  2806. }
  2807. ClearAllCommitFuncs( func );
  2808. }
  2809. //-----------------------------------------------------------------------------
  2810. // Sets the sampler state
  2811. //-----------------------------------------------------------------------------
  2812. static inline void SetSamplerState( D3DDeviceWrapper *pDevice, int stage, D3DSAMPLERSTATETYPE state, DWORD val )
  2813. {
  2814. RECORD_SAMPLER_STATE( stage, state, val );
  2815. #if defined( _X360 )
  2816. if ( state == D3DSAMP_NOTSUPPORTED )
  2817. return;
  2818. #endif
  2819. pDevice->SetSamplerState( stage, state, val );
  2820. }
  2821. inline void CShaderAPIDx8::SetSamplerState( int stage, D3DSAMPLERSTATETYPE state, DWORD val )
  2822. {
  2823. #ifndef DX_TO_GL_ABSTRACTION
  2824. if ( IsDeactivated() )
  2825. return;
  2826. #endif
  2827. ::SetSamplerState( Dx9Device(), stage, state, val );
  2828. }
  2829. //-----------------------------------------------------------------------------
  2830. // Sets the texture stage state
  2831. //-----------------------------------------------------------------------------
  2832. inline void CShaderAPIDx8::SetRenderState( D3DRENDERSTATETYPE state, DWORD val )
  2833. {
  2834. #if ( !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION ) )
  2835. {
  2836. if ( IsDeactivated() )
  2837. return;
  2838. }
  2839. # else
  2840. {
  2841. Assert( state != D3DRS_NOTSUPPORTED ); //Use SetSupportedRenderState() macro to avoid this at compile time
  2842. //if ( state == D3DRS_NOTSUPPORTED )
  2843. // return;
  2844. }
  2845. # endif
  2846. Assert( state >= 0 && ( int )state < MAX_NUM_RENDERSTATES );
  2847. if ( m_DynamicState.m_RenderState[state] != val )
  2848. {
  2849. #ifdef DX_TO_GL_ABSTRACTION
  2850. Dx9Device()->SetRenderStateInline( state, val );
  2851. #else
  2852. Dx9Device()->SetRenderState( state, val );
  2853. #endif
  2854. m_DynamicState.m_RenderState[state] = val;
  2855. }
  2856. }
  2857. #ifdef DX_TO_GL_ABSTRACTION
  2858. // Purposely always writing the new state (even if it's not changed), in case SetRenderStateConstInline() compiles away to nothing (it sometimes does)
  2859. #define SetRenderStateConstMacro(t, state, val ) do { Assert( state >= 0 && ( int )state < MAX_NUM_RENDERSTATES ); if ( t->m_DynamicState.m_RenderState[state] != (DWORD)val ) { Dx9Device()->SetRenderStateConstInline( state, val ); } t->m_DynamicState.m_RenderState[state] = val; } while(0)
  2860. #else
  2861. #define SetRenderStateConstMacro(t, state, val ) t->SetRenderState( state, val );
  2862. #endif
  2863. inline void CShaderAPIDx8::SetScreenSizeForVPOS( int pshReg /* = 32 */)
  2864. {
  2865. int nWidth, nHeight;
  2866. ITexture *pTexture = ShaderAPI()->GetRenderTargetEx( 0 );
  2867. if ( pTexture == NULL )
  2868. {
  2869. ShaderAPI()->GetBackBufferDimensions( nWidth, nHeight );
  2870. }
  2871. else
  2872. {
  2873. nWidth = pTexture->GetActualWidth();
  2874. nHeight = pTexture->GetActualHeight();
  2875. }
  2876. // Set constant to enable translation of VPOS to render target coordinates in ps_3_0
  2877. float vScreenSize[4] = { 1.0f/(float)nWidth, 1.0f/(float)nHeight, 0.5f/(float)nWidth, 0.5f/(float)nHeight };
  2878. SetPixelShaderConstantInternal( pshReg, vScreenSize, 1, true );
  2879. }
  2880. inline void CShaderAPIDx8::SetVSNearAndFarZ( int vshReg )
  2881. {
  2882. VMatrix m;
  2883. GetMatrix( MATERIAL_PROJECTION, m.m[0] );
  2884. // m[2][2] = F/(N-F) (flip sign if RH)
  2885. // m[3][2] = NF/(N-F)
  2886. float vNearFar[4];
  2887. float N = m[3][2] / m[2][2];
  2888. float F = (m[3][2]*N) / (N + m[3][2]);
  2889. vNearFar[0] = N;
  2890. vNearFar[1] = F;
  2891. SetVertexShaderConstant( vshReg, vNearFar, 1 );
  2892. }
  2893. inline float CShaderAPIDx8::GetFarZ()
  2894. {
  2895. VMatrix m;
  2896. GetMatrix( MATERIAL_PROJECTION, m.m[0] ); // See above for the algebra here
  2897. float N = m[3][2] / m[2][2];
  2898. return (m[3][2]*N) / (N + m[3][2]);
  2899. }
  2900. void CShaderAPIDx8::EnableSinglePassFlashlightMode( bool bEnable )
  2901. {
  2902. m_bSinglePassFlashlightMode = bEnable;
  2903. }
  2904. bool CShaderAPIDx8::SinglePassFlashlightModeEnabled( void )
  2905. {
  2906. return IsX360() || IsPS3() || m_bSinglePassFlashlightMode; //360/PS3 only supports single pass flashlights
  2907. }
  2908. //-----------------------------------------------------------------------------
  2909. // Commits viewports
  2910. //-----------------------------------------------------------------------------
  2911. static void CommitSetScissorRect( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce )
  2912. {
  2913. // Set the enable/disable renderstate
  2914. bool bEnableChanged = desiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] != currentState.m_RenderState[D3DRS_SCISSORTESTENABLE];
  2915. if ( bEnableChanged )
  2916. {
  2917. Dx9Device()->SetRenderState( D3DRS_SCISSORTESTENABLE, desiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] );
  2918. currentState.m_RenderState[D3DRS_SCISSORTESTENABLE] = desiredState.m_RenderState[D3DRS_SCISSORTESTENABLE];
  2919. }
  2920. // Only bother with the rect if we're enabling
  2921. if ( desiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] )
  2922. {
  2923. int nWidth, nHeight;
  2924. ITexture *pTexture = ShaderAPI()->GetRenderTargetEx( 0 );
  2925. if ( pTexture == NULL )
  2926. {
  2927. ShaderAPI()->GetBackBufferDimensions( nWidth, nHeight );
  2928. }
  2929. else
  2930. {
  2931. nWidth = pTexture->GetActualWidth();
  2932. nHeight = pTexture->GetActualHeight();
  2933. }
  2934. Assert( (desiredState.m_ScissorRect.left <= nWidth) && (desiredState.m_ScissorRect.bottom <= nHeight) &&
  2935. ( desiredState.m_ScissorRect.top >= 0 ) && (desiredState.m_ScissorRect.left >= 0) );
  2936. Dx9Device()->SetScissorRect( &desiredState.m_ScissorRect );
  2937. currentState.m_ScissorRect = desiredState.m_ScissorRect;
  2938. }
  2939. }
  2940. // Routine for setting scissor rect
  2941. // If pScissorRect is NULL, disable scissoring by setting the render state
  2942. // If pScissorRect is non-NULL, set the RECT state in Direct3D AND set the renderstate
  2943. inline void CShaderAPIDx8::SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor )
  2944. {
  2945. Assert( (nLeft <= nRight) && (nTop <= nBottom) ); //360 craps itself if this isn't true
  2946. if ( !g_pHardwareConfig->Caps().m_bScissorSupported )
  2947. return;
  2948. DWORD dwEnableScissor = bEnableScissor ? TRUE : FALSE;
  2949. RECT newScissorRect;
  2950. newScissorRect.left = nLeft;
  2951. newScissorRect.top = nTop;
  2952. newScissorRect.right = nRight;
  2953. newScissorRect.bottom = nBottom;
  2954. // If we're turning it on, check the validity of the rect
  2955. if ( bEnableScissor )
  2956. {
  2957. int nWidth, nHeight;
  2958. ITexture *pTexture = GetRenderTargetEx( 0 );
  2959. if ( pTexture == NULL )
  2960. {
  2961. GetBackBufferDimensions( nWidth, nHeight );
  2962. }
  2963. else
  2964. {
  2965. nWidth = pTexture->GetActualWidth();
  2966. nHeight = pTexture->GetActualHeight();
  2967. }
  2968. Assert( (nRight <= nWidth) && (nBottom <= nHeight) && ( nTop >= 0 ) && (nLeft >= 0) );
  2969. newScissorRect.left = clamp( newScissorRect.left, 0, nWidth );
  2970. newScissorRect.top = clamp( newScissorRect.top, 0, nHeight );
  2971. newScissorRect.right = clamp( newScissorRect.right, 0, nWidth );
  2972. newScissorRect.bottom = clamp( newScissorRect.bottom, 0, nHeight );
  2973. }
  2974. if ( !m_bResettingRenderState )
  2975. {
  2976. bool bEnableChanged = m_DesiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] != dwEnableScissor;
  2977. bool bRectChanged = memcmp( &newScissorRect, &m_DesiredState.m_ScissorRect, sizeof(RECT) ) != 0;
  2978. if ( !bEnableChanged && !bRectChanged )
  2979. return;
  2980. }
  2981. m_DesiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] = dwEnableScissor;
  2982. memcpy( &m_DesiredState.m_ScissorRect, &newScissorRect, sizeof(RECT) );
  2983. ADD_COMMIT_FUNC( COMMIT_PER_DRAW, CommitSetScissorRect );
  2984. }
  2985. inline void CShaderAPIDx8::SetRenderStateForce( D3DRENDERSTATETYPE state, DWORD val )
  2986. {
  2987. #if ( !defined( _GAMECONSOLE ) && !defined( DX_TO_GL_ABSTRACTION ) )
  2988. {
  2989. if ( IsDeactivated() ) // e.g. if the window minimized, don't set any render states
  2990. return;
  2991. }
  2992. # else
  2993. {
  2994. Assert( state != D3DRS_NOTSUPPORTED ); //Use SetSupportedRenderStateForce() macro to avoid this at compile time
  2995. //if ( state == D3DRS_NOTSUPPORTED )
  2996. // return;
  2997. }
  2998. # endif
  2999. Dx9Device()->SetRenderState( state, val );
  3000. m_DynamicState.m_RenderState[state] = val;
  3001. }
  3002. //-----------------------------------------------------------------------------
  3003. // Set the values for pixel shader constants that don't change.
  3004. //-----------------------------------------------------------------------------
  3005. void CShaderAPIDx8::SetStandardVertexShaderConstants( float fOverbright )
  3006. {
  3007. LOCK_SHADERAPI();
  3008. // Set a couple standard constants....
  3009. Vector4D standardVertexShaderConstant( 0.0f, 1.0f, 2.0f, 0.5f );
  3010. SetVertexShaderConstantInternal( VERTEX_SHADER_MATH_CONSTANTS0, standardVertexShaderConstant.Base(), 1 );
  3011. // [ gamma, overbright, 1/3, 1/overbright ]
  3012. standardVertexShaderConstant.Init( 1.0f/2.2f, fOverbright, 1.0f / 3.0f, 1.0f / fOverbright );
  3013. SetVertexShaderConstantInternal( VERTEX_SHADER_MATH_CONSTANTS1, standardVertexShaderConstant.Base(), 1 );
  3014. #if 0
  3015. int nModelIndex = VERTEX_SHADER_MODEL;
  3016. // These point to the lighting and the transforms
  3017. standardVertexShaderConstant.Init(
  3018. VERTEX_SHADER_LIGHTS,
  3019. VERTEX_SHADER_LIGHTS + 5,
  3020. // Use COLOR instead of UBYTE4 since Geforce3 does not support it
  3021. // vConst.w should be 3, but due to about hack, mul by 255 and add epsilon
  3022. // 360 supports UBYTE4, so no fixup required
  3023. (IsPC() || !IsX360()) ? 765.01f : 3.0f,
  3024. nModelIndex ); // DX8 has different constant packing
  3025. #endif
  3026. SetVertexShaderConstantInternal( VERTEX_SHADER_LIGHT_INDEX, standardVertexShaderConstant.Base(), 1 );
  3027. /*
  3028. if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_3_0 )
  3029. {
  3030. Vector4D factors[4];
  3031. factors[0].Init( 1, 0, 0, 0 );
  3032. factors[1].Init( 0, 1, 0, 0 );
  3033. factors[2].Init( 0, 0, 1, 0 );
  3034. factors[3].Init( 0, 0, 0, 1 );
  3035. SetVertexShaderConstantInternal( VERTEX_SHADER_DOT_PRODUCT_FACTORS, factors[0].Base(), 4 );
  3036. }
  3037. */
  3038. float c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  3039. SetVertexShaderConstantInternal( VERTEX_SHADER_FLEXSCALE, c, 1 );
  3040. }
  3041. //-----------------------------------------------------------------------------
  3042. // Initialize vertex and pixel shaders
  3043. //-----------------------------------------------------------------------------
  3044. void CShaderAPIDx8::InitVertexAndPixelShaders()
  3045. {
  3046. bool bPreviousState;
  3047. if ( IsX360() )
  3048. {
  3049. // to init/update all constants now, must release ownership
  3050. bPreviousState = OwnGPUResources( false );
  3051. }
  3052. // Allocate space for the pixel and vertex shader constants...
  3053. // pixel shaders
  3054. {
  3055. #ifdef _PS3
  3056. m_DynamicState.m_pVectorPixelShaderConstant = NULL;
  3057. m_DesiredState.m_pVectorPixelShaderConstant = NULL;
  3058. #else
  3059. if (m_DynamicState.m_pVectorPixelShaderConstant)
  3060. {
  3061. delete[] m_DynamicState.m_pVectorPixelShaderConstant;
  3062. }
  3063. m_DynamicState.m_pVectorPixelShaderConstant = new Vector4D[g_pHardwareConfig->Caps().m_NumPixelShaderConstants];
  3064. if (m_DesiredState.m_pVectorPixelShaderConstant)
  3065. {
  3066. delete[] m_DesiredState.m_pVectorPixelShaderConstant;
  3067. }
  3068. m_DesiredState.m_pVectorPixelShaderConstant = new Vector4D[g_pHardwareConfig->Caps().m_NumPixelShaderConstants];
  3069. #endif
  3070. if (m_DynamicState.m_pBooleanPixelShaderConstant)
  3071. {
  3072. delete[] m_DynamicState.m_pBooleanPixelShaderConstant;
  3073. }
  3074. m_DynamicState.m_pBooleanPixelShaderConstant = new BOOL[g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants];
  3075. if (m_DesiredState.m_pBooleanPixelShaderConstant)
  3076. {
  3077. delete[] m_DesiredState.m_pBooleanPixelShaderConstant;
  3078. }
  3079. m_DesiredState.m_pBooleanPixelShaderConstant = new BOOL[g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants];
  3080. if (m_DynamicState.m_pIntegerPixelShaderConstant)
  3081. {
  3082. delete[] m_DynamicState.m_pIntegerPixelShaderConstant;
  3083. }
  3084. m_DynamicState.m_pIntegerPixelShaderConstant = new IntVector4D[g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants];
  3085. if (m_DesiredState.m_pIntegerPixelShaderConstant)
  3086. {
  3087. delete[] m_DesiredState.m_pIntegerPixelShaderConstant;
  3088. }
  3089. m_DesiredState.m_pIntegerPixelShaderConstant = new IntVector4D[g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants];
  3090. // force reset vector pixel constants
  3091. int i;
  3092. #ifdef _PS3
  3093. // if ( int numResetBytes = g_pHardwareConfig->Caps().m_NumPixelShaderConstants * sizeof( float ) * 4 )
  3094. // {
  3095. // float *pResetPixelShaderConstants = ( float * ) stackalloc( numResetBytes );
  3096. // memset( pResetPixelShaderConstants, 0, numResetBytes );
  3097. // SetPixelShaderConstantInternal( 0, pResetPixelShaderConstants, g_pHardwareConfig->Caps().m_NumPixelShaderConstants, true );
  3098. // }
  3099. gpGcmDrawState->m_dirtyStatesMask |= CGcmDrawState::kDirtyZeroAllPSConsts;
  3100. #else
  3101. for ( i = 0; i < g_pHardwareConfig->Caps().m_NumPixelShaderConstants; ++i )
  3102. {
  3103. m_DesiredState.m_pVectorPixelShaderConstant[i].Init();
  3104. }
  3105. SetPixelShaderConstantInternal( 0, m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), g_pHardwareConfig->Caps().m_NumPixelShaderConstants, true );
  3106. #endif
  3107. // force reset boolean pixel constants
  3108. int nNumBooleanPixelShaderConstants = g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants;
  3109. if ( nNumBooleanPixelShaderConstants )
  3110. {
  3111. for ( i = 0; i < nNumBooleanPixelShaderConstants; ++i )
  3112. {
  3113. m_DesiredState.m_pBooleanPixelShaderConstant[i] = 0;
  3114. }
  3115. SetBooleanPixelShaderConstant( 0, m_DesiredState.m_pBooleanPixelShaderConstant, nNumBooleanPixelShaderConstants, true );
  3116. }
  3117. // force reset integer pixel constants
  3118. int nNumIntegerPixelShaderConstants = g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants;
  3119. if ( nNumIntegerPixelShaderConstants )
  3120. {
  3121. for ( i = 0; i < nNumIntegerPixelShaderConstants; ++i )
  3122. {
  3123. m_DesiredState.m_pIntegerPixelShaderConstant[i].Init();
  3124. }
  3125. SetIntegerPixelShaderConstant( 0, m_DesiredState.m_pIntegerPixelShaderConstant[0].Base(), nNumIntegerPixelShaderConstants, true );
  3126. }
  3127. }
  3128. // vertex shaders
  3129. {
  3130. if (m_DynamicState.m_pVectorVertexShaderConstant)
  3131. {
  3132. delete[] m_DynamicState.m_pVectorVertexShaderConstant;
  3133. }
  3134. m_DynamicState.m_pVectorVertexShaderConstant = new Vector4D[g_pHardwareConfig->Caps().m_NumVertexShaderConstants];
  3135. if (m_DesiredState.m_pVectorVertexShaderConstant)
  3136. {
  3137. delete[] m_DesiredState.m_pVectorVertexShaderConstant;
  3138. }
  3139. m_DesiredState.m_pVectorVertexShaderConstant = new Vector4D[g_pHardwareConfig->Caps().m_NumVertexShaderConstants];
  3140. if (m_DynamicState.m_pBooleanVertexShaderConstant)
  3141. {
  3142. delete[] m_DynamicState.m_pBooleanVertexShaderConstant;
  3143. }
  3144. m_DynamicState.m_pBooleanVertexShaderConstant = new BOOL[g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants];
  3145. if (m_DesiredState.m_pBooleanVertexShaderConstant)
  3146. {
  3147. delete[] m_DesiredState.m_pBooleanVertexShaderConstant;
  3148. }
  3149. m_DesiredState.m_pBooleanVertexShaderConstant = new BOOL[g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants];
  3150. if (m_DynamicState.m_pIntegerVertexShaderConstant)
  3151. {
  3152. delete[] m_DynamicState.m_pIntegerVertexShaderConstant;
  3153. }
  3154. m_DynamicState.m_pIntegerVertexShaderConstant = new IntVector4D[g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants];
  3155. if (m_DesiredState.m_pIntegerVertexShaderConstant)
  3156. {
  3157. delete[] m_DesiredState.m_pIntegerVertexShaderConstant;
  3158. }
  3159. m_DesiredState.m_pIntegerVertexShaderConstant = new IntVector4D[g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants];
  3160. // force reset vector vertex constants
  3161. #ifdef _PS3
  3162. int i;
  3163. memset(m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), 0,
  3164. g_pHardwareConfig->Caps().m_NumVertexShaderConstants * sizeof(vec_float4));
  3165. gpGcmDrawState->m_dirtyStatesMask |= CGcmDrawState::kDirtyZeroAllVSConsts;
  3166. #else
  3167. int i;
  3168. for ( i = 0; i < g_pHardwareConfig->Caps().m_NumVertexShaderConstants; ++i )
  3169. {
  3170. m_DesiredState.m_pVectorVertexShaderConstant[i].Init();
  3171. }
  3172. SetVertexShaderConstantInternal( 0, m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), g_pHardwareConfig->Caps().m_NumVertexShaderConstants, true );
  3173. #endif
  3174. // force reset boolean vertex constants
  3175. for ( i = 0; i < g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants; ++i )
  3176. {
  3177. m_DesiredState.m_pBooleanVertexShaderConstant[i] = 0;
  3178. }
  3179. SetBooleanVertexShaderConstant( 0, m_DesiredState.m_pBooleanVertexShaderConstant, g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants, true );
  3180. if ( !IsPS3() )
  3181. {
  3182. // force reset integer vertex constants
  3183. for ( i = 0; i < g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants; ++i )
  3184. {
  3185. m_DesiredState.m_pIntegerVertexShaderConstant[i].Init();
  3186. }
  3187. SetIntegerVertexShaderConstant( 0, m_DesiredState.m_pIntegerVertexShaderConstant[0].Base(), g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants, true );
  3188. }
  3189. }
  3190. if ( IsX360() )
  3191. {
  3192. // to init/update all constants, must disable ownership
  3193. bool bPreviousState = OwnGPUResources( false );
  3194. WriteShaderConstantsToGPU();
  3195. OwnGPUResources( bPreviousState );
  3196. }
  3197. SetStandardVertexShaderConstants( OVERBRIGHT );
  3198. // Set up the vertex and pixel shader stuff
  3199. ShaderManager()->ResetShaderState();
  3200. }
  3201. //-----------------------------------------------------------------------------
  3202. // Initialize render state
  3203. //-----------------------------------------------------------------------------
  3204. void CShaderAPIDx8::InitRenderState()
  3205. {
  3206. // Set the default shadow state
  3207. g_pShaderShadowDx8->SetDefaultState();
  3208. // Grab a snapshot of this state; we'll be using it to set the board
  3209. // state to something well defined.
  3210. m_TransitionTable.TakeDefaultStateSnapshot();
  3211. #ifdef _GAMECONSOLE
  3212. m_zPassSnapshot = m_TransitionTable.TakeSnapshot();
  3213. #endif
  3214. if ( !IsDeactivated() )
  3215. {
  3216. ResetRenderState();
  3217. }
  3218. }
  3219. //-----------------------------------------------------------------------------
  3220. // Commits vertex textures
  3221. //-----------------------------------------------------------------------------
  3222. static void CommitVertexTextures( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce )
  3223. {
  3224. int nCount = g_pMaterialSystemHardwareConfig->GetVertexSamplerCount();
  3225. for ( int i = 0; i < nCount; ++i )
  3226. {
  3227. VertexTextureState_t &currentVTState = currentState.m_VertexTextureState[i];
  3228. ShaderAPITextureHandle_t textureHandle = desiredState.m_VertexTextureState[i].m_BoundVertexTexture;
  3229. Texture_t *pTexture = ( textureHandle != INVALID_SHADERAPI_TEXTURE_HANDLE ) ? &g_ShaderAPIDX8.GetTexture( textureHandle ) : NULL;
  3230. // if ( pTexture && ( pTexture->m_Flags & Texture_t::IS_VERTEX_TEXTURE ) == 0 )
  3231. // {
  3232. // Warning( "Attempting to bind a vertex texture (%s) which was not created as a vertex texture!\n", pTexture->m_DebugName.String() );
  3233. // }
  3234. if ( bForce || ( currentVTState.m_BoundVertexTexture != textureHandle ) )
  3235. {
  3236. currentVTState.m_BoundVertexTexture = textureHandle;
  3237. // RECORD_COMMAND( DX8_SET_VERTEXTEXTURE, 3 );
  3238. // RECORD_INT( D3DVERTEXTEXTURESAMPLER0 + nStage );
  3239. // RECORD_INT( pTexture ? pTexture->GetUniqueID() : 0xFFFF );
  3240. // RECORD_INT( 0 );
  3241. IDirect3DBaseTexture *pD3DTexture = ( textureHandle >= 0 ) ? g_ShaderAPIDX8.GetD3DTexture( textureHandle ) : NULL;
  3242. pDevice->SetTexture( D3DVERTEXTEXTURESAMPLER0 + i, pD3DTexture );
  3243. }
  3244. if ( !pTexture )
  3245. continue;
  3246. D3DTEXTUREADDRESS nNewUTexWrap = (D3DTEXTUREADDRESS)pTexture->m_UTexWrap;
  3247. if ( bForce || ( currentVTState.m_UTexWrap != nNewUTexWrap ) )
  3248. {
  3249. currentVTState.m_UTexWrap = nNewUTexWrap;
  3250. SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSU, currentVTState.m_UTexWrap );
  3251. }
  3252. D3DTEXTUREADDRESS nNewVTexWrap = (D3DTEXTUREADDRESS)pTexture->m_VTexWrap;
  3253. if ( bForce || ( currentVTState.m_VTexWrap != nNewVTexWrap ) )
  3254. {
  3255. currentVTState.m_VTexWrap = nNewVTexWrap;
  3256. SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSV, currentVTState.m_VTexWrap );
  3257. }
  3258. /*
  3259. D3DTEXTUREADDRESS nNewWTexWrap = pTexture->GetWTexWrap();
  3260. if ( bForce || ( currentVTState.m_WTexWrap != nNewWTexWrap ) )
  3261. {
  3262. currentVTState.m_WTexWrap = nNewWTexWrap;
  3263. SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSW, currentVTState.m_WTexWrap );
  3264. }
  3265. */
  3266. D3DTEXTUREFILTERTYPE nNewMinFilter = (D3DTEXTUREFILTERTYPE)pTexture->m_MinFilter;
  3267. if ( bForce || ( currentVTState.m_MinFilter != nNewMinFilter ) )
  3268. {
  3269. currentVTState.m_MinFilter = nNewMinFilter;
  3270. SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MINFILTER, currentVTState.m_MinFilter );
  3271. }
  3272. D3DTEXTUREFILTERTYPE nNewMagFilter = (D3DTEXTUREFILTERTYPE)pTexture->m_MagFilter;
  3273. if ( bForce || ( currentVTState.m_MagFilter != nNewMagFilter ) )
  3274. {
  3275. currentVTState.m_MagFilter = nNewMagFilter;
  3276. SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MAGFILTER, currentVTState.m_MagFilter );
  3277. }
  3278. D3DTEXTUREFILTERTYPE nNewMipFilter = (D3DTEXTUREFILTERTYPE)pTexture->m_MipFilter;
  3279. if ( bForce || ( currentVTState.m_MipFilter != nNewMipFilter ) )
  3280. {
  3281. currentVTState.m_MipFilter = nNewMipFilter;
  3282. SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MIPFILTER, currentVTState.m_MipFilter );
  3283. }
  3284. }
  3285. }
  3286. //-----------------------------------------------------------------------------
  3287. // Returns true if the state snapshot is translucent
  3288. //-----------------------------------------------------------------------------
  3289. bool CShaderAPIDx8::IsTranslucent( StateSnapshot_t id ) const
  3290. {
  3291. LOCK_SHADERAPI();
  3292. const ShadowState_t& snapshot = m_TransitionTable.GetSnapshot(id);
  3293. return snapshot.m_AlphaBlendState.m_AlphaBlendEnable && !snapshot.m_AlphaBlendState.m_AlphaBlendEnabledForceOpaque;
  3294. }
  3295. //-----------------------------------------------------------------------------
  3296. // Returns true if the state snapshot is alpha tested
  3297. //-----------------------------------------------------------------------------
  3298. bool CShaderAPIDx8::IsAlphaTested( StateSnapshot_t id ) const
  3299. {
  3300. LOCK_SHADERAPI();
  3301. return m_TransitionTable.GetSnapshot(id).m_AlphaTestAndMiscState.m_AlphaTestEnable;
  3302. }
  3303. //-----------------------------------------------------------------------------
  3304. // Gets at the shadow state for a particular state snapshot
  3305. //-----------------------------------------------------------------------------
  3306. bool CShaderAPIDx8::IsDepthWriteEnabled( StateSnapshot_t id ) const
  3307. {
  3308. LOCK_SHADERAPI();
  3309. return m_TransitionTable.GetSnapshot(id).m_DepthTestState.m_ZWriteEnable;
  3310. }
  3311. //-----------------------------------------------------------------------------
  3312. // Returns true if the state snapshot uses shaders
  3313. //-----------------------------------------------------------------------------
  3314. bool CShaderAPIDx8::UsesVertexAndPixelShaders( StateSnapshot_t id ) const
  3315. {
  3316. LOCK_SHADERAPI();
  3317. return m_TransitionTable.GetSnapshotShader(id).m_VertexShader != INVALID_SHADER;
  3318. }
  3319. //-----------------------------------------------------------------------------
  3320. // Takes a snapshot
  3321. //-----------------------------------------------------------------------------
  3322. StateSnapshot_t CShaderAPIDx8::TakeSnapshot( )
  3323. {
  3324. LOCK_SHADERAPI();
  3325. return m_TransitionTable.TakeSnapshot();
  3326. }
  3327. void CShaderAPIDx8::ResetDXRenderState( void )
  3328. {
  3329. float zero = 0.0f;
  3330. float one = 1.0f;
  3331. DWORD dZero = *((DWORD*)(&zero));
  3332. DWORD dOne = *((DWORD*)(&one));
  3333. // Set default values for all dx render states.
  3334. // NOTE: this does not include states encapsulated by the transition table,
  3335. // which are reset in CTransitionTable::UseDefaultState
  3336. SetSupportedRenderStateForce( D3DRS_FILLMODE, D3DFILL_SOLID );
  3337. SetSupportedRenderStateForce( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
  3338. SetSupportedRenderStateForce( D3DRS_LASTPIXEL, TRUE );
  3339. SetSupportedRenderStateForce( D3DRS_CULLMODE, D3DCULL_CCW );
  3340. SetSupportedRenderStateForce( D3DRS_DITHERENABLE, FALSE );
  3341. SetSupportedRenderStateForce( D3DRS_FOGENABLE, FALSE );
  3342. SetSupportedRenderStateForce( D3DRS_SPECULARENABLE, FALSE );
  3343. SetSupportedRenderStateForce( D3DRS_FOGCOLOR, 0 );
  3344. SetSupportedRenderStateForce( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
  3345. SetSupportedRenderStateForce( D3DRS_FOGSTART, dZero );
  3346. SetSupportedRenderStateForce( D3DRS_FOGEND, dOne );
  3347. SetSupportedRenderStateForce( D3DRS_FOGDENSITY, dZero );
  3348. SetSupportedRenderStateForce( D3DRS_RANGEFOGENABLE, FALSE );
  3349. SetSupportedRenderStateForce( D3DRS_STENCILENABLE, FALSE);
  3350. SetSupportedRenderStateForce( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
  3351. SetSupportedRenderStateForce( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  3352. SetSupportedRenderStateForce( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
  3353. SetSupportedRenderStateForce( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
  3354. SetSupportedRenderStateForce( D3DRS_STENCILREF, 0 );
  3355. SetSupportedRenderStateForce( D3DRS_STENCILMASK, 0xFFFFFFFF );
  3356. SetSupportedRenderStateForce( D3DRS_STENCILWRITEMASK, 0xFFFFFFFF );
  3357. SetSupportedRenderStateForce( D3DRS_TEXTUREFACTOR, 0xFFFFFFFF );
  3358. SetSupportedRenderStateForce( D3DRS_WRAP0, 0 );
  3359. SetSupportedRenderStateForce( D3DRS_WRAP1, 0 );
  3360. SetSupportedRenderStateForce( D3DRS_WRAP2, 0 );
  3361. SetSupportedRenderStateForce( D3DRS_WRAP3, 0 );
  3362. SetSupportedRenderStateForce( D3DRS_WRAP4, 0 );
  3363. SetSupportedRenderStateForce( D3DRS_WRAP5, 0 );
  3364. SetSupportedRenderStateForce( D3DRS_WRAP6, 0 );
  3365. SetSupportedRenderStateForce( D3DRS_WRAP7, 0 );
  3366. SetSupportedRenderStateForce( D3DRS_CLIPPING, TRUE );
  3367. SetSupportedRenderStateForce( D3DRS_LIGHTING, TRUE );
  3368. SetSupportedRenderStateForce( D3DRS_AMBIENT, 0 );
  3369. SetSupportedRenderStateForce( D3DRS_FOGVERTEXMODE, D3DFOG_NONE);
  3370. SetSupportedRenderStateForce( D3DRS_COLORVERTEX, TRUE );
  3371. SetSupportedRenderStateForce( D3DRS_LOCALVIEWER, TRUE );
  3372. SetSupportedRenderStateForce( D3DRS_NORMALIZENORMALS, FALSE );
  3373. SetSupportedRenderStateForce( D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2 );
  3374. SetSupportedRenderStateForce( D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL );
  3375. SetSupportedRenderStateForce( D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL );
  3376. SetSupportedRenderStateForce( D3DRS_VERTEXBLEND, D3DVBF_DISABLE );
  3377. SetSupportedRenderStateForce( D3DRS_CLIPPLANEENABLE, 0 );
  3378. // -disable_d3d9_hacks is for debugging. For example, the "CENT" driver hack thing causes the flashlight pass to appear much brighter on NVidia drivers.
  3379. if ( IsPC() && !IsOpenGL() && !CommandLine()->CheckParm( "-disable_d3d9_hacks" ) )
  3380. {
  3381. if ( g_pHardwareConfig->Caps().m_bNeedsATICentroidHack )
  3382. {
  3383. SetSupportedRenderStateForce( D3DRS_POINTSIZE, MAKEFOURCC( 'C', 'E', 'N', 'T' ) );
  3384. }
  3385. else if ( g_pHardwareConfig->Caps().m_VendorID == VENDORID_NVIDIA )
  3386. {
  3387. // NVIDIA has a bug in their driver, so we can't call this on DX10 hardware right now
  3388. if ( !g_pHardwareConfig->UsesSRGBCorrectBlending() )
  3389. {
  3390. // This helps the driver to know to turn on fast z reject for NVidia dx80 hardware
  3391. SetSupportedRenderStateForce( D3DRS_POINTSIZE, MAKEFOURCC( 'H', 'L', '2', 'A' ) );
  3392. }
  3393. }
  3394. if( g_pHardwareConfig->Caps().m_bDisableShaderOptimizations )
  3395. {
  3396. SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_Y, MAKEFOURCC( 'C', 'O', 'P', 'M' ) );
  3397. }
  3398. }
  3399. SetSupportedRenderStateForce( D3DRS_POINTSIZE, dOne );
  3400. SetSupportedRenderStateForce( D3DRS_POINTSIZE_MIN, dOne );
  3401. SetSupportedRenderStateForce( D3DRS_POINTSPRITEENABLE, FALSE );
  3402. SetSupportedRenderStateForce( D3DRS_POINTSCALEENABLE, FALSE );
  3403. SetSupportedRenderStateForce( D3DRS_POINTSCALE_A, dOne );
  3404. SetSupportedRenderStateForce( D3DRS_POINTSCALE_B, dZero );
  3405. SetSupportedRenderStateForce( D3DRS_POINTSCALE_C, dZero );
  3406. SetSupportedRenderStateForce( D3DRS_MULTISAMPLEANTIALIAS, TRUE );
  3407. SetSupportedRenderStateForce( D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF );
  3408. SetSupportedRenderStateForce( D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE );
  3409. SetSupportedRenderStateForce( D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE );
  3410. float sixtyFour = 64.0f;
  3411. SetSupportedRenderStateForce( D3DRS_POINTSIZE_MAX, *((DWORD*)(&sixtyFour)));
  3412. SetSupportedRenderStateForce( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
  3413. SetSupportedRenderStateForce( D3DRS_TWEENFACTOR, dZero );
  3414. SetSupportedRenderStateForce( D3DRS_POSITIONDEGREE, D3DDEGREE_CUBIC );
  3415. SetSupportedRenderStateForce( D3DRS_NORMALDEGREE, D3DDEGREE_LINEAR );
  3416. SetSupportedRenderStateForce( D3DRS_SCISSORTESTENABLE, FALSE);
  3417. SetSupportedRenderStateForce( D3DRS_SLOPESCALEDEPTHBIAS, dZero );
  3418. SetSupportedRenderStateForce( D3DRS_ANTIALIASEDLINEENABLE, FALSE );
  3419. SetSupportedRenderStateForce( D3DRS_MINTESSELLATIONLEVEL, dOne );
  3420. SetSupportedRenderStateForce( D3DRS_MAXTESSELLATIONLEVEL, dOne );
  3421. SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_X, dZero );
  3422. SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_Y, dZero );
  3423. SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_Z, dOne );
  3424. SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_W, dZero );
  3425. SetSupportedRenderStateForce( D3DRS_ENABLEADAPTIVETESSELLATION, FALSE );
  3426. SetSupportedRenderStateForce( D3DRS_TWOSIDEDSTENCILMODE, FALSE );
  3427. SetSupportedRenderStateForce( D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP );
  3428. SetSupportedRenderStateForce( D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP );
  3429. SetSupportedRenderStateForce( D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP );
  3430. SetSupportedRenderStateForce( D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS );
  3431. SetSupportedRenderStateForce( D3DRS_COLORWRITEENABLE1, 0x0000000f );
  3432. SetSupportedRenderStateForce( D3DRS_COLORWRITEENABLE2, 0x0000000f );
  3433. SetSupportedRenderStateForce( D3DRS_COLORWRITEENABLE3, 0x0000000f );
  3434. SetSupportedRenderStateForce( D3DRS_BLENDFACTOR, 0xffffffff );
  3435. SetSupportedRenderStateForce( D3DRS_SRGBWRITEENABLE, 0);
  3436. SetSupportedRenderStateForce( D3DRS_DEPTHBIAS, dZero );
  3437. SetSupportedRenderStateForce( D3DRS_WRAP8, 0 );
  3438. SetSupportedRenderStateForce( D3DRS_WRAP9, 0 );
  3439. SetSupportedRenderStateForce( D3DRS_WRAP10, 0 );
  3440. SetSupportedRenderStateForce( D3DRS_WRAP11, 0 );
  3441. SetSupportedRenderStateForce( D3DRS_WRAP12, 0 );
  3442. SetSupportedRenderStateForce( D3DRS_WRAP13, 0 );
  3443. SetSupportedRenderStateForce( D3DRS_WRAP14, 0 );
  3444. SetSupportedRenderStateForce( D3DRS_WRAP15, 0 );
  3445. SetSupportedRenderStateForce( D3DRS_BLENDOP, D3DBLENDOP_ADD );
  3446. SetSupportedRenderStateForce( D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD );
  3447. #if defined( _X360 )
  3448. SetSupportedRenderStateForce( D3DRS_HIZENABLE, mat_hi_z_enable.GetBool() ? D3DHIZ_AUTOMATIC : D3DHIZ_DISABLE );
  3449. SetSupportedRenderStateForce( D3DRS_HIZWRITEENABLE, D3DHIZ_AUTOMATIC );
  3450. SetSupportedRenderStateForce( D3DRS_HISTENCILENABLE, FALSE );
  3451. SetSupportedRenderStateForce( D3DRS_HISTENCILWRITEENABLE, FALSE );
  3452. SetSupportedRenderStateForce( D3DRS_HISTENCILFUNC, D3DHSCMP_EQUAL );
  3453. SetSupportedRenderStateForce( D3DRS_HISTENCILREF, 0 );
  3454. #endif
  3455. }
  3456. //-----------------------------------------------------------------------------
  3457. // Own GPU Resources. Return previous state. GPU Ownership allows the code
  3458. // to defer all constant setting and then just blast the peak watermark directly into
  3459. // the system's internal command buffer. The actual savings may be very negligible
  3460. // if not worse due to our constant layout, which causes a wider range to be
  3461. // copied.
  3462. //-----------------------------------------------------------------------------
  3463. bool CShaderAPIDx8::OwnGPUResources( bool bEnable )
  3464. {
  3465. #if defined( _X360 )
  3466. // no longer supporting, causes an unmeasurable benefit
  3467. // code complexity and instability dictate it is better left off
  3468. // modelfastpath and better batching has probably lessened the dense amount of constant setting
  3469. // leaving code in case perf testing again shows constant setting to be an issue
  3470. if ( !IsGPUOwnSupported() )
  3471. {
  3472. return false;
  3473. }
  3474. if ( m_bGPUOwned == bEnable )
  3475. {
  3476. return m_bGPUOwned;
  3477. }
  3478. if ( !bEnable )
  3479. {
  3480. Dx9Device()->GpuDisownAll();
  3481. }
  3482. else
  3483. {
  3484. // owned GPU constants can be set very fast, and must be in blocks of 4
  3485. // owned constants are set via a peak watermark, otherwise the legacy method is used
  3486. // there are 256, but the game only uses 217 (snapped to 220), leaving just enough room for shader literals
  3487. COMPILE_TIME_ASSERT( VERTEX_SHADER_MODEL + 3*NUM_MODEL_TRANSFORMS == 217 );
  3488. Dx9Device()->GpuOwnVertexShaderConstantF( 0, AlignValue( VERTEX_SHADER_MODEL + 3*NUM_MODEL_TRANSFORMS, 4 ) );
  3489. // there are 256, but the game only utilizes 32, leaving lots of room for shader literals
  3490. Dx9Device()->GpuOwnPixelShaderConstantF( 0, 32 );
  3491. }
  3492. bool bPrevious = m_bGPUOwned;
  3493. m_bGPUOwned = bEnable;
  3494. return bPrevious;
  3495. #else
  3496. return false;
  3497. #endif
  3498. }
  3499. //-----------------------------------------------------------------------------
  3500. // Reset render state (to its initial value)
  3501. //-----------------------------------------------------------------------------
  3502. void CShaderAPIDx8::ResetRenderState( bool bFullReset )
  3503. {
  3504. if ( IsDeactivated() )
  3505. return;
  3506. LOCK_SHADERAPI();
  3507. RECORD_DEBUG_STRING( "BEGIN ResetRenderState" );
  3508. // force xbox to do any reset work immediately
  3509. OwnGPUResources( false );
  3510. ClearAllCommitFuncs( COMMIT_PER_DRAW );
  3511. ClearAllCommitFuncs( COMMIT_PER_PASS );
  3512. m_bResettingRenderState = true;
  3513. ResetDXRenderState();
  3514. // We're not currently rendering anything
  3515. m_nCurrentSnapshot = -1;
  3516. D3DXMatrixIdentity( &m_CachedPolyOffsetProjectionMatrix );
  3517. D3DXMatrixIdentity( &m_CachedFastClipProjectionMatrix );
  3518. D3DXMatrixIdentity( &m_CachedFastClipPolyOffsetProjectionMatrix );
  3519. m_UsingTextureRenderTarget = false;
  3520. m_SceneFogColor[0] = 0;
  3521. m_SceneFogColor[1] = 0;
  3522. m_SceneFogColor[2] = 0;
  3523. m_SceneFogMode = MATERIAL_FOG_NONE;
  3524. // This is state that isn't part of the snapshot per-se, because we
  3525. // don't need it when it's actually time to render. This just helps us
  3526. // to construct the shadow state.
  3527. m_DynamicState.m_ClearColor = D3DCOLOR_XRGB(0,0,0);
  3528. UpdateDepthBiasState();
  3529. if ( bFullReset )
  3530. {
  3531. InitVertexAndPixelShaders();
  3532. }
  3533. else
  3534. {
  3535. // just need to dirty the dynamic state, desired state gets copied into below
  3536. #ifndef _PS3
  3537. Q_memset( m_DynamicState.m_pVectorPixelShaderConstant, 0, g_pHardwareConfig->Caps().m_NumPixelShaderConstants * sizeof( Vector4D ) );
  3538. #endif
  3539. Q_memset( m_DynamicState.m_pBooleanPixelShaderConstant, 0, g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants * sizeof( BOOL ) );
  3540. Q_memset( m_DynamicState.m_pIntegerPixelShaderConstant, 0, g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants * sizeof( IntVector4D ) );
  3541. Q_memset( m_DynamicState.m_pVectorVertexShaderConstant, 0, g_pHardwareConfig->Caps().m_NumVertexShaderConstants * sizeof( Vector4D ) );
  3542. #ifdef _PS3
  3543. Q_memset( m_DesiredState.m_pVectorVertexShaderConstant, 0, g_pHardwareConfig->Caps().m_NumVertexShaderConstants * sizeof( Vector4D ) );
  3544. gpGcmDrawState->m_dirtyStatesMask |= CGcmDrawState::kDirtyZeroAllVSConsts;
  3545. #endif
  3546. Q_memset( m_DynamicState.m_pBooleanVertexShaderConstant, 0, g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants * sizeof( BOOL ) );
  3547. Q_memset( m_DynamicState.m_pIntegerVertexShaderConstant, 0, g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants * sizeof( IntVector4D ) );
  3548. SetStandardVertexShaderConstants( OVERBRIGHT );
  3549. }
  3550. m_DynamicState.m_nLocalEnvCubemapSamplers = 0;
  3551. m_DynamicState.m_nLightmapSamplers = 0;
  3552. m_DynamicState.m_nPaintmapSamplers = 0;
  3553. // Set the default compressed depth range written to dest alpha. Only need to compress it for 8bit alpha to get a useful gradient.
  3554. SetFloatRenderingParameter( FLOAT_RENDERPARM_DEST_ALPHA_DEPTH_SCALE, ( g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) ? 8192.0f : 192.0f );
  3555. // Fog
  3556. m_VertexShaderFogParams[0] = m_VertexShaderFogParams[1] = 0.0f;
  3557. m_WorldSpaceCameraPosition.Init( 0, 0, 0 );
  3558. m_WorldSpaceCameraDirection.Init( 0, 0, -1 );
  3559. m_DynamicState.m_FogColor = 0xFFFFFFFF;
  3560. m_DynamicState.m_vecPixelFogColor.Init();
  3561. m_DynamicState.m_vecPixelFogColorLinear.Init();
  3562. m_DynamicState.m_bFogGammaCorrectionDisabled = false;
  3563. m_DynamicState.m_FogEnable = false;
  3564. m_DynamicState.m_FogMode = D3DFOG_NONE;
  3565. m_DynamicState.m_FogStart = -1;
  3566. m_DynamicState.m_FogEnd = -1;
  3567. m_DynamicState.m_FogMaxDensity = -1.0f;
  3568. m_DynamicState.m_FogZ = 0.0f;
  3569. SetSupportedRenderState( D3DRS_FOGCOLOR, m_DynamicState.m_FogColor );
  3570. SetSupportedRenderState( D3DRS_FOGENABLE, m_DynamicState.m_FogEnable );
  3571. SetSupportedRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
  3572. SetSupportedRenderState( D3DRS_FOGVERTEXMODE, D3DFOG_NONE );
  3573. SetSupportedRenderState( D3DRS_RANGEFOGENABLE, false );
  3574. FogStart( 0 );
  3575. FogEnd( 0 );
  3576. FogMaxDensity( 1.0f );
  3577. m_DynamicState.m_bSRGBWritesEnabled = false;
  3578. // Set the cull mode
  3579. m_DynamicState.m_bCullEnabled = true;
  3580. m_DynamicState.m_CullMode = D3DCULL_CCW;
  3581. m_DynamicState.m_DesiredCullMode = D3DCULL_CCW;
  3582. SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
  3583. // No shade mode yet
  3584. m_DynamicState.m_ShadeMode = (D3DSHADEMODE)-1;
  3585. ShadeMode( SHADER_SMOOTH );
  3586. m_DynamicState.m_bHWMorphingEnabled = false;
  3587. // Skinning...
  3588. m_DynamicState.m_NumBones = 0;
  3589. // It's safe and not a perf problem to always enable this renderstate, even for single-sample rendertargets
  3590. SetRenderState( D3DRS_MULTISAMPLEANTIALIAS, true );
  3591. if ( g_pHardwareConfig->ActualCaps().m_bSupportsAlphaToCoverage )
  3592. {
  3593. D3DRENDERSTATETYPE renderState = (D3DRENDERSTATETYPE)g_pHardwareConfig->ActualCaps().m_AlphaToCoverageState;
  3594. SetRenderState( renderState, g_pHardwareConfig->ActualCaps().m_AlphaToCoverageDisableValue ); // Vendor dependent state
  3595. }
  3596. // Anisotropic filtering is disabled by default
  3597. if ( bFullReset )
  3598. {
  3599. SetAnisotropicLevel( 1 );
  3600. }
  3601. for ( int i = 0; i < g_pHardwareConfig->ActualCaps().m_NumSamplers; ++i )
  3602. {
  3603. SamplerState(i).m_BoundTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
  3604. SamplerState(i).m_UTexWrap = D3DTADDRESS_WRAP;
  3605. SamplerState(i).m_VTexWrap = D3DTADDRESS_WRAP;
  3606. SamplerState(i).m_WTexWrap = D3DTADDRESS_WRAP;
  3607. SamplerState(i).m_MagFilter = D3DTEXF_POINT;
  3608. SamplerState(i).m_MinFilter = D3DTEXF_POINT;
  3609. SamplerState(i).m_MipFilter = D3DTEXF_NONE;
  3610. SamplerState(i).m_TextureEnable = false;
  3611. SamplerState(i).m_nTextureBindFlags = TEXTURE_BINDFLAGS_NONE;
  3612. SamplerState(i).m_bShadowFilterEnable = 0;
  3613. // Just some initial state...
  3614. Dx9Device()->SetTexture( i, 0 );
  3615. SetSamplerState( i, D3DSAMP_ADDRESSU, SamplerState(i).m_UTexWrap );
  3616. SetSamplerState( i, D3DSAMP_ADDRESSV, SamplerState(i).m_VTexWrap );
  3617. SetSamplerState( i, D3DSAMP_ADDRESSW, SamplerState(i).m_WTexWrap );
  3618. SetSamplerState( i, D3DSAMP_MINFILTER, SamplerState(i).m_MinFilter );
  3619. SetSamplerState( i, D3DSAMP_MAGFILTER, SamplerState(i).m_MagFilter );
  3620. SetSamplerState( i, D3DSAMP_MIPFILTER, SamplerState(i).m_MipFilter );
  3621. #if defined ( POSIX )
  3622. SetSamplerState( i, D3DSAMP_SHADOWFILTER, SamplerState(i).m_bShadowFilterEnable );
  3623. #endif
  3624. SetSamplerState( i, D3DSAMP_BORDERCOLOR, RGB( 0,0,0 ) );
  3625. }
  3626. // FIXME!!!!! : This barfs with the debug runtime on 6800.
  3627. for( int i = 0; i < g_pHardwareConfig->ActualCaps().m_NumVertexSamplers; i++ )
  3628. {
  3629. m_DynamicState.m_VertexTextureState[i].m_BoundVertexTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
  3630. Dx9Device()->SetTexture( D3DVERTEXTEXTURESAMPLER0 + i, NULL );
  3631. m_DynamicState.m_VertexTextureState[i].m_UTexWrap = D3DTADDRESS_CLAMP;
  3632. m_DynamicState.m_VertexTextureState[i].m_VTexWrap = D3DTADDRESS_CLAMP;
  3633. // m_DynamicState.m_VertexTextureState[i].m_WTexWrap = D3DTADDRESS_CLAMP;
  3634. m_DynamicState.m_VertexTextureState[i].m_MinFilter = D3DTEXF_POINT;
  3635. m_DynamicState.m_VertexTextureState[i].m_MagFilter = D3DTEXF_POINT;
  3636. m_DynamicState.m_VertexTextureState[i].m_MipFilter = D3DTEXF_POINT;
  3637. SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSU, m_DynamicState.m_VertexTextureState[i].m_UTexWrap );
  3638. SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSV, m_DynamicState.m_VertexTextureState[i].m_VTexWrap );
  3639. // SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSW, m_DynamicState.m_VertexTextureState[i].m_WTexWrap );
  3640. SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MINFILTER, m_DynamicState.m_VertexTextureState[i].m_MinFilter );
  3641. SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MAGFILTER, m_DynamicState.m_VertexTextureState[i].m_MagFilter );
  3642. SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MIPFILTER, m_DynamicState.m_VertexTextureState[i].m_MipFilter );
  3643. }
  3644. memset( &m_DynamicState.m_InstanceInfo, 0, sizeof(InstanceInfo_t) );
  3645. memset( &m_DynamicState.m_CompiledLightingState, 0, sizeof(CompiledLightingState_t) );
  3646. memset( &m_DynamicState.m_LightingState, 0, sizeof( MaterialLightingState_t ) );
  3647. for ( int i = 0; i < NUM_MATRIX_MODES; ++i)
  3648. {
  3649. // By setting this to *not* be identity, we force an update...
  3650. m_DynamicState.m_TransformType[i] = TRANSFORM_IS_GENERAL;
  3651. m_DynamicState.m_TransformChanged[i] = STATE_CHANGED;
  3652. }
  3653. // set the board state to match the default state
  3654. m_TransitionTable.UseDefaultState();
  3655. // Set the default render state
  3656. SetDefaultState();
  3657. // Constant for all time
  3658. SetSupportedRenderState( D3DRS_CLIPPING, TRUE );
  3659. SetSupportedRenderState( D3DRS_LOCALVIEWER, TRUE );
  3660. SetSupportedRenderState( D3DRS_POINTSCALEENABLE, FALSE );
  3661. #if 0
  3662. float fBias = -1.0f;
  3663. SetTextureStageState( 0, D3DTSS_MIPMAPLODBIAS, *( ( LPDWORD ) (&fBias) ) );
  3664. SetTextureStageState( 1, D3DTSS_MIPMAPLODBIAS, *( ( LPDWORD ) (&fBias) ) );
  3665. SetTextureStageState( 2, D3DTSS_MIPMAPLODBIAS, *( ( LPDWORD ) (&fBias) ) );
  3666. SetTextureStageState( 3, D3DTSS_MIPMAPLODBIAS, *( ( LPDWORD ) (&fBias) ) );
  3667. #endif
  3668. if ( bFullReset )
  3669. {
  3670. // Set the modelview matrix to identity too
  3671. for ( int i = 0; i < NUM_MODEL_TRANSFORMS; ++i )
  3672. {
  3673. SetIdentityMatrix( m_boneMatrix[i] );
  3674. }
  3675. MatrixMode( MATERIAL_VIEW );
  3676. LoadIdentity();
  3677. MatrixMode( MATERIAL_PROJECTION );
  3678. LoadIdentity();
  3679. }
  3680. #ifdef _X360
  3681. m_DynamicState.m_bBuffer2Frames = m_bBuffer2FramesAhead;
  3682. SetRenderState( D3DRS_BUFFER2FRAMES, m_DynamicState.m_bBuffer2Frames );
  3683. #endif
  3684. m_DynamicState.m_Viewport.X = m_DynamicState.m_Viewport.Y =
  3685. m_DynamicState.m_Viewport.Width = m_DynamicState.m_Viewport.Height = (DWORD)-1;
  3686. m_DynamicState.m_Viewport.MinZ = m_DynamicState.m_Viewport.MaxZ = 0.0;
  3687. // Be sure scissoring is off
  3688. m_DynamicState.m_RenderState[D3DRS_SCISSORTESTENABLE] = FALSE;
  3689. SetRenderState( D3DRS_SCISSORTESTENABLE, FALSE );
  3690. m_DynamicState.m_ScissorRect.left = -1;
  3691. m_DynamicState.m_ScissorRect.top = -1;
  3692. m_DynamicState.m_ScissorRect.right = -1;
  3693. m_DynamicState.m_ScissorRect.bottom = -1;
  3694. //SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  3695. EnableFastClip( false );
  3696. float fFakePlane[4];
  3697. unsigned int iFakePlaneVal = 0xFFFFFFFF;
  3698. fFakePlane[0] = fFakePlane[1] = fFakePlane[2] = fFakePlane[3] = *((float *)&iFakePlaneVal);
  3699. SetFastClipPlane( fFakePlane ); //doing this to better wire up plane change detection
  3700. float zero[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  3701. // Make sure that our state is dirty.
  3702. m_DynamicState.m_UserClipPlaneEnabled = 0;
  3703. m_DynamicState.m_UserClipPlaneChanged = 0;
  3704. m_DynamicState.m_UserClipLastUpdatedUsingFixedFunction = false;
  3705. for ( int i = 0; i < g_pHardwareConfig->MaxUserClipPlanes(); i++ )
  3706. {
  3707. // Make sure that our state is dirty.
  3708. m_DynamicState.m_UserClipPlaneWorld[i][0] = -1.0f;
  3709. m_DynamicState.m_UserClipPlaneProj[i][0] = -9999.0f;
  3710. m_DynamicState.m_UserClipPlaneEnabled |= ( 1 << i );
  3711. SetClipPlane( i, zero );
  3712. EnableClipPlane( i, false );
  3713. Assert( m_DynamicState.m_UserClipPlaneEnabled == 0 );
  3714. }
  3715. Assert( m_DynamicState.m_UserClipPlaneChanged == ((1 << g_pHardwareConfig->MaxUserClipPlanes()) - 1) );
  3716. m_DynamicState.m_FastClipEnabled = false;
  3717. m_DynamicState.m_bFastClipPlaneChanged = true;
  3718. // User clip override
  3719. m_DynamicState.m_bUserClipTransformOverride = false;
  3720. D3DXMatrixIdentity( &m_DynamicState.m_UserClipTransform );
  3721. // Viewport defaults to the window size
  3722. RECT windowRect;
  3723. #if defined(_WIN32) && !defined( DX_TO_GL_ABSTRACTION )
  3724. GetClientRect( (HWND)m_hWnd, &windowRect );
  3725. #else
  3726. toglGetClientRect( (VD3DHWND)m_hWnd, &windowRect );
  3727. #endif
  3728. ShaderViewport_t viewport;
  3729. viewport.Init( windowRect.left, windowRect.top,
  3730. windowRect.right - windowRect.left, windowRect.bottom - windowRect.top );
  3731. SetViewports( 1, &viewport, true );
  3732. // No render mesh
  3733. m_pRenderMesh = 0;
  3734. m_nRenderInstanceCount = 0;
  3735. m_pRenderInstances = NULL;
  3736. m_pRenderCompiledState = NULL;
  3737. m_pRenderInstanceInfo = NULL;
  3738. m_bRenderHasSetStencil = false;
  3739. // Reset cached vertex decl
  3740. m_DynamicState.m_pVertexDecl = NULL;
  3741. m_DynamicState.m_DeclVertexFormat = 0;
  3742. m_DynamicState.m_bDeclHasColorMesh = false;
  3743. m_DynamicState.m_bDeclUsingFlex = false;
  3744. m_DynamicState.m_bDeclUsingMorph = false;
  3745. m_DynamicState.m_bDeclUsingPreTessPatch = false;
  3746. // Reset the render target to be the normal backbuffer
  3747. if ( IsX360() )
  3748. {
  3749. m_hCachedRenderTarget = INVALID_SHADERAPI_TEXTURE_HANDLE;
  3750. m_bUsingSRGBRenderTarget = false;
  3751. }
  3752. AcquireInternalRenderTargets();
  3753. SetRenderTarget();
  3754. if ( !bFullReset )
  3755. {
  3756. // Full reset has already allocated and inited the default values and sent them (above).
  3757. // Normal reset sends the desired values.
  3758. if ( g_pHardwareConfig->Caps().m_NumVertexShaderConstants != 0 )
  3759. {
  3760. #ifndef _PS3
  3761. // 217 on X360 to play nice with fast blatting code
  3762. SetVertexShaderConstantInternal( 0, m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), IsX360() ? 217 : g_pHardwareConfig->Caps().m_NumVertexShaderConstants, true );
  3763. #endif
  3764. }
  3765. if ( g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants != 0 )
  3766. {
  3767. SetIntegerVertexShaderConstant( 0, (int *)m_DesiredState.m_pIntegerVertexShaderConstant, g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants, true );
  3768. }
  3769. if ( g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants != 0 )
  3770. {
  3771. SetBooleanVertexShaderConstant( 0, m_DesiredState.m_pBooleanVertexShaderConstant, g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants, true );
  3772. }
  3773. if ( g_pHardwareConfig->Caps().m_NumPixelShaderConstants != 0 )
  3774. {
  3775. #ifndef _PS3
  3776. SetPixelShaderConstantInternal( 0, m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), g_pHardwareConfig->Caps().m_NumPixelShaderConstants, true );
  3777. #endif
  3778. }
  3779. if ( g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants != 0 )
  3780. {
  3781. SetIntegerPixelShaderConstant( 0, (int *)m_DesiredState.m_pIntegerPixelShaderConstant, g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants, true );
  3782. }
  3783. if ( g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants != 0 )
  3784. {
  3785. SetBooleanPixelShaderConstant( 0, m_DesiredState.m_pBooleanPixelShaderConstant, g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants, true );
  3786. }
  3787. }
  3788. // apply any queued commits that have 'desired' state
  3789. CallCommitFuncs( COMMIT_PER_DRAW, true );
  3790. CallCommitFuncs( COMMIT_PER_PASS, true );
  3791. //
  3792. // All state setting now completed
  3793. //
  3794. // save vertex/pixel shader constant pointers
  3795. Vector4D *pVectorPixelShaderConstants = m_DesiredState.m_pVectorPixelShaderConstant;
  3796. int *pBooleanPixelShaderConstants = m_DesiredState.m_pBooleanPixelShaderConstant;
  3797. IntVector4D *pIntegerPixelShaderConstants = m_DesiredState.m_pIntegerPixelShaderConstant;
  3798. Vector4D *pVectorVertexShaderConstants = m_DesiredState.m_pVectorVertexShaderConstant;
  3799. int *pBooleanVertexShaderConstants = m_DesiredState.m_pBooleanVertexShaderConstant;
  3800. IntVector4D *pIntegerVertexShaderConstants = m_DesiredState.m_pIntegerVertexShaderConstant;
  3801. // DesiredState = DynamicState
  3802. memcpy( &m_DesiredState, &m_DynamicState, sizeof( DynamicState_t ) );
  3803. // restore vertex/pixel shader constant pointers
  3804. m_DesiredState.m_pVectorPixelShaderConstant = pVectorPixelShaderConstants;
  3805. m_DesiredState.m_pBooleanPixelShaderConstant = pBooleanPixelShaderConstants;
  3806. m_DesiredState.m_pIntegerPixelShaderConstant = pIntegerPixelShaderConstants;
  3807. m_DesiredState.m_pVectorVertexShaderConstant = pVectorVertexShaderConstants;
  3808. m_DesiredState.m_pBooleanVertexShaderConstant = pBooleanVertexShaderConstants;
  3809. m_DesiredState.m_pIntegerVertexShaderConstant = pIntegerVertexShaderConstants;
  3810. m_bResettingRenderState = false;
  3811. OwnGPUResources( true );
  3812. RECORD_DEBUG_STRING( "END ResetRenderState" );
  3813. }
  3814. //-----------------------------------------------------------------------------
  3815. // Sets the default render state
  3816. //-----------------------------------------------------------------------------
  3817. void CShaderAPIDx8::SetDefaultState()
  3818. {
  3819. LOCK_SHADERAPI();
  3820. CShaderAPIDx8::MatrixMode( MATERIAL_MODEL );
  3821. CShaderAPIDx8::ShadeMode( SHADER_SMOOTH );
  3822. CShaderAPIDx8::SetVertexShaderIndex( );
  3823. CShaderAPIDx8::SetPixelShaderIndex( );
  3824. MeshMgr()->MarkUnusedVertexFields( 0, 0, NULL );
  3825. }
  3826. //-----------------------------------------------------------------------------
  3827. //
  3828. // Methods related to vertex format
  3829. //
  3830. //-----------------------------------------------------------------------------
  3831. //-----------------------------------------------------------------------------
  3832. // Sets the vertex
  3833. //-----------------------------------------------------------------------------
  3834. inline void CShaderAPIDx8::SetVertexDecl( VertexFormat_t vertexFormat, bool bHasColorMesh, bool bUsingFlex, bool bUsingMorph, bool bUsingPreTessPatch, VertexStreamSpec_t *pStreamSpec )
  3835. {
  3836. VPROF("CShaderAPIDx8::SetVertexDecl");
  3837. if ( pStreamSpec || vertexFormat != m_DynamicState.m_DeclVertexFormat ||
  3838. bHasColorMesh != m_DynamicState.m_bDeclHasColorMesh ||
  3839. bUsingFlex != m_DynamicState.m_bDeclUsingFlex ||
  3840. bUsingMorph != m_DynamicState.m_bDeclUsingMorph ||
  3841. bUsingPreTessPatch != m_DynamicState.m_bDeclUsingPreTessPatch )
  3842. {
  3843. IDirect3DVertexDeclaration9 *pDecl = FindOrCreateVertexDecl( vertexFormat, bHasColorMesh, bUsingFlex, bUsingMorph, bUsingPreTessPatch, pStreamSpec );
  3844. Assert( pDecl );
  3845. if ( ( pDecl != m_DynamicState.m_pVertexDecl ) && pDecl )
  3846. {
  3847. Dx9Device()->SetVertexDeclaration( pDecl );
  3848. m_DynamicState.m_pVertexDecl = pDecl;
  3849. }
  3850. m_DynamicState.m_DeclVertexFormat = vertexFormat;
  3851. m_DynamicState.m_bDeclHasColorMesh = bHasColorMesh;
  3852. m_DynamicState.m_bDeclUsingFlex = bUsingFlex;
  3853. m_DynamicState.m_bDeclUsingMorph = bUsingMorph;
  3854. m_DynamicState.m_bDeclUsingPreTessPatch = bUsingPreTessPatch;
  3855. }
  3856. }
  3857. void CShaderAPIDx8::SetTessellationMode( TessellationMode_t mode )
  3858. {
  3859. m_DynamicState.m_TessellationMode = mode;
  3860. }
  3861. //-----------------------------------------------------------------------------
  3862. //
  3863. // Methods related to vertex buffers
  3864. //
  3865. //-----------------------------------------------------------------------------
  3866. IMesh *CShaderAPIDx8::GetFlexMesh()
  3867. {
  3868. LOCK_SHADERAPI();
  3869. return MeshMgr()->GetFlexMesh();
  3870. }
  3871. //-----------------------------------------------------------------------------
  3872. // Gets the dynamic mesh
  3873. //-----------------------------------------------------------------------------
  3874. IMesh* CShaderAPIDx8::GetDynamicMesh( IMaterial* pMaterial, int nHWSkinBoneCount, bool buffered,
  3875. IMesh* pVertexOverride, IMesh* pIndexOverride )
  3876. {
  3877. Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
  3878. LOCK_SHADERAPI();
  3879. return MeshMgr()->GetDynamicMesh( pMaterial, 0, nHWSkinBoneCount, buffered, pVertexOverride, pIndexOverride );
  3880. }
  3881. IMesh* CShaderAPIDx8::GetDynamicMeshEx( IMaterial* pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount,
  3882. bool bBuffered, IMesh* pVertexOverride, IMesh* pIndexOverride )
  3883. {
  3884. Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
  3885. LOCK_SHADERAPI();
  3886. return MeshMgr()->GetDynamicMesh( pMaterial, vertexFormat, nHWSkinBoneCount, bBuffered, pVertexOverride, pIndexOverride );
  3887. }
  3888. //-----------------------------------------------------------------------------
  3889. // Returns the number of vertices we can render using the dynamic mesh
  3890. //-----------------------------------------------------------------------------
  3891. void CShaderAPIDx8::GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices )
  3892. {
  3893. LOCK_SHADERAPI();
  3894. MeshMgr()->GetMaxToRender( pMesh, bMaxUntilFlush, pMaxVerts, pMaxIndices );
  3895. }
  3896. int CShaderAPIDx8::GetMaxVerticesToRender( IMaterial *pMaterial )
  3897. {
  3898. pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion(); //always work with the realtime version internally
  3899. LOCK_SHADERAPI();
  3900. return MeshMgr()->GetMaxVerticesToRender( pMaterial );
  3901. }
  3902. int CShaderAPIDx8::GetMaxIndicesToRender( )
  3903. {
  3904. LOCK_SHADERAPI();
  3905. return MeshMgr()->GetMaxIndicesToRender( );
  3906. }
  3907. void CShaderAPIDx8::MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords )
  3908. {
  3909. LOCK_SHADERAPI();
  3910. MeshMgr()->MarkUnusedVertexFields( nFlags, nTexCoordCount, pUnusedTexCoords );
  3911. }
  3912. #ifdef _GAMECONSOLE
  3913. //-----------------------------------------------------------------------------
  3914. // Backdoor used by the queued context to directly use write-combined memory
  3915. //-----------------------------------------------------------------------------
  3916. IMesh *CShaderAPIDx8::GetExternalMesh( const ExternalMeshInfo_t& info )
  3917. {
  3918. LOCK_SHADERAPI();
  3919. return MeshMgr()->GetExternalMesh( info );
  3920. }
  3921. void CShaderAPIDx8::SetExternalMeshData( IMesh *pMesh, const ExternalMeshData_t &data )
  3922. {
  3923. LOCK_SHADERAPI();
  3924. return MeshMgr()->SetExternalMeshData( pMesh, data );
  3925. }
  3926. IIndexBuffer *CShaderAPIDx8::GetExternalIndexBuffer( int nIndexCount, uint16 *pIndexData )
  3927. {
  3928. LOCK_SHADERAPI();
  3929. return MeshMgr()->GetExternalIndexBuffer( nIndexCount, pIndexData );
  3930. }
  3931. void CShaderAPIDx8::FlushGPUCache( void *pBaseAddr, size_t nSizeInBytes )
  3932. {
  3933. #ifdef _X360
  3934. if ( nSizeInBytes > 0 )
  3935. {
  3936. Dx9Device()->InvalidateGpuCache( pBaseAddr, nSizeInBytes, 0 );
  3937. }
  3938. #elif _PS3
  3939. Dx9Device()->FlushVertexCache(); // @TODO@
  3940. #endif
  3941. }
  3942. #endif
  3943. const char *_gShaderName;
  3944. //-----------------------------------------------------------------------------
  3945. // Draws the mesh
  3946. //-----------------------------------------------------------------------------
  3947. void CShaderAPIDx8::DrawMesh( CMeshBase *pMesh, int nCount, const MeshInstanceData_t *pInstances,
  3948. VertexCompressionType_t nCompressionType, CompiledLightingState_t* pCompiledState,
  3949. InstanceInfo_t *pInfo )
  3950. {
  3951. Assert( nCount > 0 );
  3952. VPROF("CShaderAPIDx8::DrawMesh");
  3953. if ( ShaderUtil()->GetConfig().m_bSuppressRendering )
  3954. return;
  3955. if ( m_pMaterial )
  3956. {
  3957. if ( IShader *pShader = m_pMaterial->GetShader() )
  3958. {
  3959. _gShaderName = pShader->GetName();
  3960. if ( !strcmp( _gShaderName, "VertexLitGeneric" ) )
  3961. {
  3962. m_bVtxLitMesh = true;
  3963. }
  3964. else if ( !strcmp( _gShaderName, "LightmappedGeneric" ) )
  3965. {
  3966. m_bLmapMesh = true;
  3967. }
  3968. else if ( !strcmp( _gShaderName, "UnlitGeneric" ) )
  3969. {
  3970. m_bUnlitMesh = true;
  3971. }
  3972. }
  3973. }
  3974. if (m_bGeneratingCSMs)
  3975. {
  3976. if (!(m_bVtxLitMesh || m_bLmapMesh || m_bUnlitMesh))
  3977. {
  3978. DrawShadowMesh(pMesh, nCount, pInstances, nCompressionType, pCompiledState, pInfo);
  3979. }
  3980. goto xit;
  3981. }
  3982. else if (m_bVtxLitMesh || m_bLmapMesh || m_bUnlitMesh)
  3983. {
  3984. DrawMesh2(pMesh, nCount, pInstances, nCompressionType, pCompiledState, pInfo);
  3985. goto xit;
  3986. }
  3987. // If we are here then it's neither vtx lit, lmap or shadows
  3988. DrawMeshInternal( pMesh, nCount, pInstances, nCompressionType, pCompiledState, pInfo );
  3989. // Stop profiling
  3990. xit:
  3991. m_bVtxLitMesh = false;
  3992. m_bLmapMesh = false;
  3993. m_bUnlitMesh = false;
  3994. }
  3995. void CShaderAPIDx8::DrawMeshInternal( CMeshBase *pMesh, int nCount, const MeshInstanceData_t *pInstances,
  3996. VertexCompressionType_t nCompressionType, CompiledLightingState_t* pCompiledState,
  3997. InstanceInfo_t *pInfo )
  3998. {
  3999. #if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) || ( defined( PLATFORM_POSIX ) && ( GLMDEBUG > 0 ) ) )
  4000. BeginPIXEvent( PIX_VALVE_ORANGE, s_pPIXMaterialName );
  4001. #endif
  4002. m_pRenderMesh = pMesh;
  4003. m_nRenderInstanceCount = nCount;
  4004. m_pRenderInstances = pInstances;
  4005. m_pRenderCompiledState = pCompiledState;
  4006. m_pRenderInstanceInfo = pInfo;
  4007. m_bRenderHasSetStencil = false;
  4008. m_DynamicState.m_bLightStateComputed = false;
  4009. m_DynamicState.m_nLocalEnvCubemapSamplers = 0;
  4010. m_DynamicState.m_nLightmapSamplers = 0;
  4011. m_DynamicState.m_nPaintmapSamplers = 0;
  4012. GetCurrentStencilState( &m_RenderInitialStencilState );
  4013. bool bUsingPreTessPatches = false;
  4014. if ( m_pRenderMesh )
  4015. {
  4016. VertexFormat_t vertexFormat = m_pRenderMesh->GetVertexFormat();
  4017. bUsingPreTessPatches = ( m_pRenderMesh->GetTessellationType() > 0 ) && ( GetTessellationMode() == TESSELLATION_MODE_ACC_PATCHES_EXTRA || GetTessellationMode() == TESSELLATION_MODE_ACC_PATCHES_REG );
  4018. SetVertexDecl( vertexFormat, ( m_pMaterial->GetVertexFormat() & VERTEX_COLOR_STREAM_1 ) != 0, m_pRenderMesh->HasFlexMesh(),
  4019. m_pMaterial->IsUsingVertexID(), bUsingPreTessPatches, m_pRenderMesh->GetVertexStreamSpec() );
  4020. }
  4021. bool bIsAlphaModulating = pInstances[0].m_DiffuseModulation[3] != 1.0f;
  4022. #ifdef _DEBUG
  4023. // NOTE: At the moment, if one instance is modulating, they all are.
  4024. // However, this is relatively easy to fix; I just don't have time.
  4025. // Each shader render pass needs to store 2 alphablending states: one for when we are alpha
  4026. // modulating and one when were are not. All shaders need to be rewritten
  4027. // to not have either static or dynamic combos as a result of modulating/not modulating
  4028. // Then this will work.
  4029. for ( int i = 1; i < nCount; ++i )
  4030. {
  4031. bool bTestIsAlphaModulating = pInstances[i].m_DiffuseModulation[3] != 1.0f;
  4032. Assert( bTestIsAlphaModulating == bIsAlphaModulating );
  4033. }
  4034. #endif
  4035. CommitStateChanges();
  4036. Assert( m_pMaterial );
  4037. m_pMaterial->DrawMesh( nCompressionType, bIsAlphaModulating, bUsingPreTessPatches );
  4038. if ( m_bRenderHasSetStencil )
  4039. {
  4040. SetStencilStateInternal( m_RenderInitialStencilState );
  4041. }
  4042. m_pRenderMesh = NULL;
  4043. m_nRenderInstanceCount = 0;
  4044. m_pRenderInstances = NULL;
  4045. m_pRenderCompiledState = NULL;
  4046. m_pRenderInstanceInfo = NULL;
  4047. m_bRenderHasSetStencil = false;
  4048. m_DynamicState.m_bLightStateComputed = false;
  4049. #if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) || ( defined( PLATFORM_POSIX ) && ( GLMDEBUG > 0 ) ) )
  4050. EndPIXEvent();
  4051. #endif
  4052. }
  4053. void CShaderAPIDx8::DrawMesh2( CMeshBase* pMesh, int nCount, const MeshInstanceData_t *pInstances,
  4054. VertexCompressionType_t nCompressionType, CompiledLightingState_t* pCompiledState, InstanceInfo_t *pInfo )
  4055. {
  4056. int bFixedLightingMode;
  4057. bool inFlashlightMode;
  4058. uint32 mtlChangeTimestamp;
  4059. bool bIsAlphaModulating;
  4060. int modulationFlags;
  4061. CBasePerMaterialContextData **pContextDataPtr;
  4062. int dynVSIdx, dynPSIdx;
  4063. IShader *pShader;
  4064. IMaterialVar** params;
  4065. bool mtlChanged;
  4066. static ConVarRef r_staticlight_mode( "r_staticlight_mode" );
  4067. if ( (m_bVtxLitMesh && !mat_vtxlit_new_path.GetBool()) ||
  4068. (m_bLmapMesh && !mat_lmap_new_path.GetBool()) ||
  4069. (m_bUnlitMesh && !mat_unlit_new_path.GetBool()) )
  4070. {
  4071. goto useOldPath;
  4072. }
  4073. // old path only if using avg of 3 staticlight color streams, since we fall back to sm2b
  4074. if ( r_staticlight_mode.GetInt() == 1 )
  4075. {
  4076. goto useOldPath;
  4077. }
  4078. // Work out if this mesh can indeed use the new path
  4079. if ( m_bToolsMode )
  4080. {
  4081. goto useOldPath;
  4082. }
  4083. // Get the context data ptr
  4084. bIsAlphaModulating = pInstances[0].m_DiffuseModulation[3] != 1.0f;
  4085. modulationFlags = bIsAlphaModulating? SHADER_USING_ALPHA_MODULATION : 0;
  4086. pContextDataPtr = m_pMaterial->GetContextData( modulationFlags );
  4087. if ( !pContextDataPtr || !(*pContextDataPtr) )
  4088. {
  4089. goto useOldPath;
  4090. }
  4091. mtlChangeTimestamp = m_pMaterial->GetChangeTimestamp();
  4092. mtlChanged = (*pContextDataPtr)->m_nVarChangeID != mtlChangeTimestamp;
  4093. if ( mtlChanged )
  4094. {
  4095. goto useOldPath;
  4096. }
  4097. inFlashlightMode = InFlashlightMode();
  4098. if ( inFlashlightMode )
  4099. {
  4100. goto useOldPath;
  4101. }
  4102. bFixedLightingMode = GetIntRenderingParameter( INT_RENDERPARM_ENABLE_FIXED_LIGHTING );
  4103. if ( bFixedLightingMode != ENABLE_FIXED_LIGHTING_NONE )
  4104. {
  4105. goto useOldPath;
  4106. }
  4107. // Possibly new path
  4108. m_pRenderMesh = pMesh;
  4109. m_nRenderInstanceCount = nCount;
  4110. m_pRenderInstances = pInstances;
  4111. m_pRenderCompiledState = pCompiledState;
  4112. m_pRenderInstanceInfo = pInfo;
  4113. m_bRenderHasSetStencil = false;
  4114. m_DynamicState.m_bLightStateComputed = false;
  4115. m_DynamicState.m_nLocalEnvCubemapSamplers = 0;
  4116. m_DynamicState.m_nLightmapSamplers = 0;
  4117. m_DynamicState.m_nPaintmapSamplers = 0;
  4118. // Streams already set by the time we get here
  4119. pShader = m_pMaterial->GetShader();
  4120. params = m_pMaterial->GetVars();
  4121. pShader->SetPPParams( params );
  4122. pShader->SetModulationFlags( modulationFlags );
  4123. pShader->ExecuteFastPath( &dynVSIdx, &dynPSIdx, params, this, nCompressionType, pContextDataPtr, m_bCSMsValidThisFrame );
  4124. if ( dynVSIdx != -1 )
  4125. {
  4126. unsigned char* pInstanceCommandBuffer = NULL;
  4127. StateSnapshot_t snapshotId = m_pMaterial->GetSnapshotId( modulationFlags, 0 );
  4128. CommitSetViewports( Dx9Device(), m_DesiredState, m_DynamicState, false );
  4129. ClearAllCommitFuncs( COMMIT_PER_DRAW );
  4130. CommitFastClipPlane();
  4131. CommitVertexShaderTransforms();
  4132. if (m_DynamicState.m_UserClipPlaneEnabled)
  4133. {
  4134. CommitUserClipPlanes();
  4135. }
  4136. m_TransitionTable.UseSnapshot( snapshotId, false );
  4137. pInstanceCommandBuffer = m_pMaterial->GetInstanceCommandBuffer( modulationFlags );
  4138. ShadowShaderState_t *pShadowShaderState = m_TransitionTable.GetShaderShadowState( snapshotId );
  4139. PixelShader_t ps = pShadowShaderState->m_PixelShader;
  4140. HardwareShader_t hps = ShaderManager()->GetPixelShader( ps, dynPSIdx );
  4141. ShaderManager()->SetPixelShaderState_Internal( hps, 0 );
  4142. VertexShader_t vs = pShadowShaderState->m_VertexShader;
  4143. HardwareShader_t hvs = ShaderManager()->GetVertexShader( vs, dynVSIdx );
  4144. ShaderManager()->SetVertexShaderState_Internal( hvs, 0 );
  4145. if ( pMesh )
  4146. {
  4147. // Set vertex decl
  4148. VertexFormat_t vertexFormat = pMesh->GetVertexFormat();
  4149. SetVertexDecl( vertexFormat, ( m_pMaterial->GetVertexFormat() & VERTEX_COLOR_STREAM_1 ) != 0, pMesh->HasFlexMesh(),
  4150. m_pMaterial->IsUsingVertexID(), false, pMesh->GetVertexStreamSpec() );
  4151. pMesh->DrawPrims( pInstanceCommandBuffer );
  4152. }
  4153. else
  4154. {
  4155. MeshMgr()->DrawInstancedPrims( pInstanceCommandBuffer );
  4156. }
  4157. pShader->SetPPParams(NULL);
  4158. }
  4159. else
  4160. {
  4161. // Could not take new path
  4162. pShader->SetPPParams(NULL);
  4163. goto useOldPath;
  4164. }
  4165. goto xit;
  4166. useOldPath:
  4167. DrawMeshInternal( pMesh, nCount, pInstances, nCompressionType, pCompiledState, pInfo );
  4168. goto xit;
  4169. xit:
  4170. m_pRenderMesh = NULL;
  4171. m_nRenderInstanceCount = 0;
  4172. m_pRenderInstances = NULL;
  4173. m_pRenderCompiledState = NULL;
  4174. m_pRenderInstanceInfo = NULL;
  4175. m_bRenderHasSetStencil = false;
  4176. m_DynamicState.m_bLightStateComputed = false;
  4177. return;
  4178. }
  4179. void CShaderAPIDx8::DrawShadowMesh( CMeshBase *pMesh, int nCount, const MeshInstanceData_t *pInstances,
  4180. VertexCompressionType_t nCompressionType, CompiledLightingState_t* pCompiledState,
  4181. InstanceInfo_t *pInfo )
  4182. {
  4183. if ( !mat_depthwrite_new_path.GetBool() )
  4184. {
  4185. DrawMeshInternal( pMesh, nCount, pInstances, nCompressionType, pCompiledState, pInfo );
  4186. return;
  4187. }
  4188. // New DrawMesh
  4189. // Work out shaders to set
  4190. int dynVSIdx, dynPSIdx;
  4191. IShader *pShader = m_pMaterial->GetShader();
  4192. IMaterialVar** params = m_pMaterial->GetVars();
  4193. pShader->SetPPParams( params );
  4194. pShader->ExecuteFastPath( &dynVSIdx, &dynPSIdx, params, this, nCompressionType, NULL, false );
  4195. if ( dynVSIdx != -1 )
  4196. {
  4197. StateSnapshot_t snapshotId = m_pMaterial->GetSnapshotId( 0, 0 );
  4198. ShadowShaderState_t *pShadowShaderState = m_TransitionTable.GetShaderShadowState( snapshotId );
  4199. if (m_DynamicState.m_UserClipPlaneEnabled)
  4200. {
  4201. CommitUserClipPlanes();
  4202. }
  4203. PixelShader_t ps = pShadowShaderState->m_PixelShader;
  4204. HardwareShader_t hps;
  4205. if ( ps != (PixelShader_t)-1 )
  4206. {
  4207. hps = ShaderManager()->GetPixelShader( ps, dynPSIdx );
  4208. }
  4209. else
  4210. {
  4211. hps = 0;
  4212. }
  4213. ShaderManager()->SetPixelShaderState_Internal( hps, 0 );
  4214. VertexShader_t vs = pShadowShaderState->m_VertexShader;
  4215. HardwareShader_t hvs = ShaderManager()->GetVertexShader( vs, dynVSIdx );
  4216. ShaderManager()->SetVertexShaderState_Internal( hvs, 0 );
  4217. if ( pMesh )
  4218. {
  4219. // Set skinning matrices if required
  4220. int numBones = GetCurrentNumBones();
  4221. if ( numBones > 0 )
  4222. {
  4223. SetSkinningMatrices( pInstances[0] );
  4224. }
  4225. // Work out vertex format. This involves an RB Tree lookup.
  4226. VertexFormat_t vertexFormat = pMesh->GetVertexFormat();
  4227. SetVertexDecl( vertexFormat, ( m_pMaterial->GetVertexFormat() & VERTEX_COLOR_STREAM_1 ) != 0, pMesh->HasFlexMesh(),
  4228. false, false, pMesh->GetVertexStreamSpec() );
  4229. // Draw
  4230. pMesh->DrawPrims( NULL );
  4231. }
  4232. else
  4233. {
  4234. MeshMgr()->DrawInstancedPrims( NULL );
  4235. }
  4236. }
  4237. else
  4238. {
  4239. //DevMsg("DrawShadowMesh: Bad dyn vs/ps index, cannot draw\n");
  4240. // gurjeets - Found bug on de_cbble where a couple of meshes get drawn into the CSM using Sprite_DX9, which actually
  4241. // turns Alpha Blending and Colour Writes ON for the CSM render target. This is wrong.
  4242. // The original DrawMesh deals with this by resetting the correct states when drawing subsequent (legit) meshes into the CSM.
  4243. // DrawShadowMesh doesn't cope because it relies on correct states being set at the start of CSM rendering
  4244. // No idea why de-cbble is trying to include some sprites in the CSM pass. They don't make it into the CSM anyway
  4245. // I expect all geometry that is legit for CSM to be drawn using one of the shaders that have a FastPath version. Testing
  4246. // a bunch of maps seems to indicate this is reasonable expectation. If we find some objects not casting shadows where
  4247. // they should be I'll revisit this.
  4248. }
  4249. pShader->SetPPParams( NULL );
  4250. }
  4251. void CShaderAPIDx8::DrawWithVertexAndIndexBuffers( void )
  4252. {
  4253. VPROF("CShaderAPIDx8::DrawWithVertexAndIndexBuffers");
  4254. if ( ShaderUtil()->GetConfig().m_bSuppressRendering )
  4255. return;
  4256. #if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) || ( defined( PLATFORM_POSIX ) && ( GLMDEBUG > 0 ) ) )
  4257. BeginPIXEvent( PIX_VALVE_ORANGE, s_pPIXMaterialName );
  4258. #endif
  4259. // m_pRenderMesh = pMesh;
  4260. // FIXME: need to make this deal with multiple streams, etc.
  4261. VertexFormat_t vertexFormat = MeshMgr()->GetCurrentVertexFormat();
  4262. SetVertexDecl( vertexFormat, false /*( vertexFormat & VERTEX_COLOR_STEAM_1 ) != 0*/,
  4263. false /*m_pRenderMesh->HasFlexMesh()*/, false /*m_pRenderMesh->IsUsingMorphData()*/,
  4264. false /*using pre tessellated patches*/,
  4265. NULL /*m_pRenderMesh->GetVertexStreamSpec()*/ );
  4266. CommitStateChanges();
  4267. if ( m_pMaterial )
  4268. {
  4269. // FIXME: Get alpha modulation state from instance information
  4270. m_pMaterial->DrawMesh( CompressionType( vertexFormat ), m_pMaterial->GetAlphaModulation() != 1.0f, false );
  4271. }
  4272. else
  4273. {
  4274. MeshMgr()->RenderPassWithVertexAndIndexBuffers( NULL );
  4275. }
  4276. // m_pRenderMesh = NULL;
  4277. #if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) || ( defined( PLATFORM_POSIX ) && ( GLMDEBUG > 0 ) ) )
  4278. EndPIXEvent();
  4279. #endif
  4280. }
  4281. //-----------------------------------------------------------------------------
  4282. // Discards the vertex buffers
  4283. //-----------------------------------------------------------------------------
  4284. void CShaderAPIDx8::DiscardVertexBuffers()
  4285. {
  4286. MeshMgr()->DiscardVertexBuffers();
  4287. }
  4288. void CShaderAPIDx8::ForceHardwareSync_WithManagedTexture()
  4289. {
  4290. if ( IsGameConsole() || IsOSX() || !m_pFrameSyncTexture )
  4291. return;
  4292. #ifndef _PS3
  4293. // Set the default state for everything so we don't get more than we ask for here!
  4294. SetDefaultState();
  4295. D3DLOCKED_RECT rect;
  4296. HRESULT hr = m_pFrameSyncTexture->LockRect( 0, &rect, NULL, 0 );
  4297. if ( SUCCEEDED( hr ) )
  4298. {
  4299. // modify..
  4300. unsigned long *pData = (unsigned long*)rect.pBits;
  4301. (*pData)++;
  4302. m_pFrameSyncTexture->UnlockRect( 0 );
  4303. // Now draw something with this texture.
  4304. DWORD iStage = 0;
  4305. IDirect3DBaseTexture9 *pOldTexture;
  4306. hr = Dx9Device()->GetTexture( iStage, &pOldTexture );
  4307. if ( SUCCEEDED( hr ) )
  4308. {
  4309. Dx9Device()->SetTexture( iStage, m_pFrameSyncTexture );
  4310. // Remember the old FVF.
  4311. DWORD oldFVF;
  4312. hr = Dx9Device()->GetFVF( &oldFVF );
  4313. if ( SUCCEEDED( hr ) )
  4314. {
  4315. // Set the new FVF.
  4316. Dx9Device()->SetFVF( D3DFVF_XYZ );
  4317. // Now, draw the simplest primitive D3D has ever seen.
  4318. unsigned short indices[3] = { 0, 1, 2 };
  4319. Vector verts[3] = {vec3_origin, vec3_origin, vec3_origin};
  4320. Dx9Device()->DrawIndexedPrimitiveUP(
  4321. D3DPT_TRIANGLELIST,
  4322. 0, // Min vertex index
  4323. 3, // Num vertices used
  4324. 1, // # primitives
  4325. indices, // indices
  4326. D3DFMT_INDEX16, // index format
  4327. verts, // Vertices
  4328. sizeof( Vector )// Vertex stride
  4329. );
  4330. Dx9Device()->SetFVF( oldFVF );
  4331. }
  4332. Dx9Device()->SetTexture( iStage, pOldTexture );
  4333. }
  4334. }
  4335. // If this assert fails, then we failed somewhere above.
  4336. AssertOnce( SUCCEEDED( hr ) );
  4337. #endif // !_PS3
  4338. }
  4339. void CShaderAPIDx8::UpdateFrameSyncQuery( int queryIndex, bool bIssue )
  4340. {
  4341. if ( IsOSX() )
  4342. return;
  4343. Assert(queryIndex < NUM_FRAME_SYNC_QUERIES);
  4344. // wait if already issued
  4345. if ( m_bQueryIssued[queryIndex] )
  4346. {
  4347. double flStartTime = Plat_FloatTime();
  4348. BOOL dummyData = 0;
  4349. HRESULT hr = S_OK;
  4350. // NOTE: This fix helps out motherboards that are a little freaky.
  4351. // On such boards, sometimes the driver has to reset itself (an event which takes several seconds)
  4352. // and when that happens, the frame sync query object gets lost
  4353. for (;;)
  4354. {
  4355. hr = m_pFrameSyncQueryObject[queryIndex]->GetData( &dummyData, sizeof( dummyData ), D3DGETDATA_FLUSH );
  4356. if ( hr != S_FALSE )
  4357. break;
  4358. double flCurrTime = Plat_FloatTime();
  4359. // don't wait more than 200ms (5fps) for these
  4360. if ( flCurrTime - flStartTime > 0.200f )
  4361. break;
  4362. // Avoid burning a full core while waiting for the query. Spinning can actually harm performance
  4363. // because there might be driver threads that are trying to do work that end up starved, and the
  4364. // power drawn by the CPU may take away from the power available to the integrated graphics chip.
  4365. // A sleep of one millisecond should never be long enough to affect performance.
  4366. ThreadSleep( 1 );
  4367. }
  4368. m_bQueryIssued[queryIndex] = false;
  4369. Assert(hr == S_OK || hr == D3DERR_DEVICELOST);
  4370. if ( hr == D3DERR_DEVICELOST )
  4371. {
  4372. MarkDeviceLost( );
  4373. return;
  4374. }
  4375. }
  4376. if ( bIssue )
  4377. {
  4378. m_pFrameSyncQueryObject[queryIndex]->Issue( D3DISSUE_END );
  4379. m_bQueryIssued[queryIndex] = true;
  4380. }
  4381. }
  4382. void CShaderAPIDx8::ForceHardwareSync( void )
  4383. {
  4384. LOCK_SHADERAPI();
  4385. VPROF( "CShaderAPIDx8::ForceHardwareSync" );
  4386. PERF_STATS_BLOCK( "CShaderAPIDx8::ForceHardwareSync", PERF_STATS_SLOT_FORCE_HARDWARE_SYNC );
  4387. TM_ZONE_PLOT( TELEMETRY_LEVEL1, "ForceHardwareSync", TELEMETRY_ZONE_PLOT_SLOT_4);
  4388. #ifdef DX_TO_GL_ABSTRACTION
  4389. if ( true )
  4390. #else
  4391. if ( !mat_frame_sync_enable.GetInt() )
  4392. #endif
  4393. return;
  4394. RECORD_COMMAND( DX8_HARDWARE_SYNC, 0 );
  4395. #if !defined( _X360 )
  4396. // How do you query dx9 for how many frames behind the hardware is or, alternatively, how do you tell the hardware to never be more than N frames behind?
  4397. // 1) The old QueryPendingFrameCount design was removed. It was
  4398. // a simple transaction with the driver through the
  4399. // GetDriverState, trivial for the drivers to lie. We came up
  4400. // with a much better scheme for tracking pending frames where
  4401. // the driver can not lie without a possible performance loss:
  4402. // use the asynchronous query system with D3DQUERYTYPE_EVENT and
  4403. // data size 0. When GetData returns S_OK for the query, you
  4404. // know that frame has finished.
  4405. if ( mat_frame_sync_force_texture.GetBool() )
  4406. {
  4407. ForceHardwareSync_WithManagedTexture();
  4408. }
  4409. else if ( m_pFrameSyncQueryObject[0] )
  4410. {
  4411. // FIXME: Could install a callback into the materialsystem to do something while waiting for
  4412. // the frame to finish (update sound, etc.)
  4413. m_currentSyncQuery ++;
  4414. if ( m_currentSyncQuery >= ARRAYSIZE(m_pFrameSyncQueryObject) )
  4415. {
  4416. m_currentSyncQuery = 0;
  4417. }
  4418. double fStart = Plat_FloatTime();
  4419. int waitIndex = ((m_currentSyncQuery + NUM_FRAME_SYNC_QUERIES) - (NUM_FRAME_SYNC_FRAMES_LATENCY+1)) % NUM_FRAME_SYNC_QUERIES;
  4420. UpdateFrameSyncQuery( waitIndex, false );
  4421. UpdateFrameSyncQuery( m_currentSyncQuery, true );
  4422. }
  4423. #else
  4424. DWORD hFence = Dx9Device()->InsertFence();
  4425. Dx9Device()->BlockOnFence( hFence );
  4426. #endif
  4427. }
  4428. //-----------------------------------------------------------------------------
  4429. // Needs render state
  4430. //-----------------------------------------------------------------------------
  4431. void CShaderAPIDx8::QueueResetRenderState()
  4432. {
  4433. m_bResetRenderStateNeeded = true;
  4434. }
  4435. //-----------------------------------------------------------------------------
  4436. // Use this to begin and end the frame
  4437. //-----------------------------------------------------------------------------
  4438. void CShaderAPIDx8::BeginFrame()
  4439. {
  4440. LOCK_SHADERAPI();
  4441. if ( m_bResetRenderStateNeeded )
  4442. {
  4443. ResetRenderState( false );
  4444. m_bResetRenderStateNeeded = false;
  4445. }
  4446. #if ALLOW_SMP_ACCESS
  4447. Dx9Device()->SetASyncMode( mat_use_smp.GetBool() );
  4448. #endif
  4449. ++m_CurrentFrame;
  4450. m_nTextureMemoryUsedLastFrame = 0;
  4451. m_bCSMsValidThisFrame = false;
  4452. }
  4453. void CShaderAPIDx8::EndFrame()
  4454. {
  4455. LOCK_SHADERAPI();
  4456. #if !defined( _X360 )
  4457. MEMCHECK;
  4458. #endif
  4459. #if SHADERAPI_BUFFER_D3DCALLS
  4460. Dx9Device()->ExecuteAllWork();
  4461. #endif
  4462. ExportTextureList();
  4463. }
  4464. int CShaderAPIDx8::D3DFormatToBitsPerPixel( D3DFORMAT fmt ) const
  4465. {
  4466. switch( fmt )
  4467. {
  4468. case D3DFMT_UNKNOWN:
  4469. return 0;
  4470. #if !( defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION ) )
  4471. case D3DFMT_R3G3B2:
  4472. case D3DFMT_P8:
  4473. case D3DFMT_A4L4:
  4474. #endif
  4475. case D3DFMT_A8:
  4476. case D3DFMT_L8:
  4477. return 8;
  4478. #if !( defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION ) )
  4479. case D3DFMT_A8R3G3B2:
  4480. case D3DFMT_A8P8:
  4481. case D3DFMT_D16_LOCKABLE:
  4482. case D3DFMT_D15S1:
  4483. #endif
  4484. case D3DFMT_R5G6B5:
  4485. case D3DFMT_X1R5G5B5:
  4486. case D3DFMT_A1R5G5B5:
  4487. case D3DFMT_A4R4G4B4:
  4488. case D3DFMT_D16:
  4489. case D3DFMT_A8L8:
  4490. case D3DFMT_V8U8:
  4491. #ifndef DX_TO_GL_ABSTRACTION
  4492. case D3DFMT_X4R4G4B4:
  4493. case D3DFMT_L6V5U5:
  4494. case D3DFMT_L16:
  4495. case D3DFMT_R16F:
  4496. #endif
  4497. return 16;
  4498. #if !defined( _X360 )
  4499. case D3DFMT_R8G8B8:
  4500. return 24;
  4501. #endif
  4502. #if !( defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION ) )
  4503. case D3DFMT_D24X4S4:
  4504. case D3DFMT_D32F_LOCKABLE:
  4505. #endif
  4506. case D3DFMT_A8R8G8B8:
  4507. case D3DFMT_X8R8G8B8:
  4508. case D3DFMT_X8L8V8U8:
  4509. case D3DFMT_Q8W8V8U8:
  4510. case D3DFMT_D24S8:
  4511. case D3DFMT_D24X8:
  4512. #ifndef DX_TO_GL_ABSTRACTION
  4513. case D3DFMT_A2B10G10R10:
  4514. case D3DFMT_A8B8G8R8:
  4515. case D3DFMT_X8B8G8R8:
  4516. case D3DFMT_G16R16:
  4517. case D3DFMT_A2R10G10B10:
  4518. case D3DFMT_V16U16:
  4519. case D3DFMT_A2W10V10U10:
  4520. case D3DFMT_R8G8_B8G8:
  4521. case D3DFMT_G8R8_G8B8:
  4522. case D3DFMT_D32:
  4523. case D3DFMT_D24FS8:
  4524. case D3DFMT_G16R16F:
  4525. case D3DFMT_R32F:
  4526. #endif
  4527. return 32;
  4528. case D3DFMT_A16B16G16R16:
  4529. case D3DFMT_A16B16G16R16F:
  4530. #ifndef DX_TO_GL_ABSTRACTION
  4531. case D3DFMT_Q16W16V16U16:
  4532. case D3DFMT_G32R32F:
  4533. #endif
  4534. return 64;
  4535. case D3DFMT_A32B32G32R32F:
  4536. return 128;
  4537. #if !( defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION ) )
  4538. case D3DFMT_MULTI2_ARGB8:
  4539. case D3DFMT_CxV8U8:
  4540. case D3DFMT_DXT2:
  4541. case D3DFMT_DXT4:
  4542. #endif
  4543. #ifndef DX_TO_GL_ABSTRACTION
  4544. case D3DFMT_UYVY:
  4545. case D3DFMT_YUY2:
  4546. #endif
  4547. case D3DFMT_DXT1:
  4548. case D3DFMT_DXT3:
  4549. case D3DFMT_DXT5:
  4550. Assert( !"Implement me" );
  4551. return 0;
  4552. default:
  4553. Assert( !"Unknown D3DFORMAT" );
  4554. return 0;
  4555. }
  4556. return 0;
  4557. }
  4558. void CShaderAPIDx8::AddBufferToTextureList( const char *pName, D3DSURFACE_DESC &desc )
  4559. {
  4560. // ImageFormat imageFormat;
  4561. // imageFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
  4562. // if( imageFormat < 0 )
  4563. // {
  4564. // Assert( 0 );
  4565. // return;
  4566. // }
  4567. int nBpp = D3DFormatToBitsPerPixel( desc.Format );
  4568. KeyValues *pSubKey = m_pDebugTextureList->CreateNewKey();
  4569. pSubKey->SetString( "Name", pName );
  4570. pSubKey->SetString( "TexGroup", TEXTURE_GROUP_RENDER_TARGET );
  4571. pSubKey->SetInt( "Size",
  4572. // ImageLoader::SizeInBytes( imageFormat ) * desc.Width * desc.Height );
  4573. nBpp * desc.Width * desc.Height * MAX( 1, desc.MultiSampleType ) / 8 );
  4574. char pTmpBuf[64];
  4575. sprintf( pTmpBuf, "%d bit buffer", nBpp );
  4576. pSubKey->SetString( "Format", pTmpBuf );//ImageLoader::GetName( imageFormat ) );
  4577. pSubKey->SetInt( "Width", desc.Width );
  4578. pSubKey->SetInt( "Height", desc.Height );
  4579. pSubKey->SetInt( "BindsMax", 1 );
  4580. pSubKey->SetInt( "BindsFrame", 1 );
  4581. }
  4582. void CShaderAPIDx8::ExportTextureList()
  4583. {
  4584. if ( !m_bEnableDebugTextureList )
  4585. return;
  4586. if ( !m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT] || !m_pZBufferSurface )
  4587. // Device vanished...
  4588. return;
  4589. m_DebugTextureListLock.Lock();
  4590. m_nDebugDataExportFrame = m_CurrentFrame;
  4591. if ( IsPC() || !IsX360() )
  4592. {
  4593. if ( m_pDebugTextureList )
  4594. m_pDebugTextureList->deleteThis();
  4595. m_pDebugTextureList = new KeyValues( "TextureList" );
  4596. m_nTextureMemoryUsedTotal = 0;
  4597. m_nTextureMemoryUsedPicMip1 = 0;
  4598. m_nTextureMemoryUsedPicMip2 = 0;
  4599. for ( ShaderAPITextureHandle_t hTexture = m_Textures.Head() ; hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
  4600. {
  4601. Texture_t &tex = m_Textures[hTexture];
  4602. if ( !( tex.m_Flags & Texture_t::IS_ALLOCATED ) )
  4603. continue;
  4604. // Compute total texture memory usage
  4605. m_nTextureMemoryUsedTotal += tex.GetMemUsage();
  4606. // Compute picmip memory usage
  4607. {
  4608. int numBytes = tex.GetMemUsage();
  4609. if ( tex.m_NumLevels > 1 )
  4610. {
  4611. if ( tex.GetWidth() > 4 || tex.GetHeight() > 4 || tex.GetDepth() > 4 )
  4612. {
  4613. int topmipsize = ImageLoader::GetMemRequired( tex.GetWidth(), tex.GetHeight(), tex.GetDepth(), tex.GetImageFormat(), false );
  4614. numBytes -= topmipsize;
  4615. m_nTextureMemoryUsedPicMip1 += numBytes;
  4616. if ( tex.GetWidth() > 8 || tex.GetHeight() > 8 || tex.GetDepth() > 8 )
  4617. {
  4618. int othermipsizeRatio = ( ( tex.GetWidth() > 8 ) ? 2 : 1 ) * ( ( tex.GetHeight() > 8 ) ? 2 : 1 ) * ( ( tex.GetDepth() > 8 ) ? 2 : 1 );
  4619. int othermipsize = topmipsize / othermipsizeRatio;
  4620. numBytes -= othermipsize;
  4621. }
  4622. m_nTextureMemoryUsedPicMip1 += numBytes;
  4623. }
  4624. else
  4625. {
  4626. m_nTextureMemoryUsedPicMip1 += numBytes;
  4627. m_nTextureMemoryUsedPicMip2 += numBytes;
  4628. }
  4629. }
  4630. else
  4631. {
  4632. m_nTextureMemoryUsedPicMip1 += numBytes;
  4633. m_nTextureMemoryUsedPicMip2 += numBytes;
  4634. }
  4635. }
  4636. if ( !m_bDebugGetAllTextures &&
  4637. tex.m_LastBoundFrame != m_CurrentFrame )
  4638. continue;
  4639. if ( tex.m_LastBoundFrame != m_CurrentFrame )
  4640. tex.m_nTimesBoundThisFrame = 0;
  4641. KeyValues *pSubKey = m_pDebugTextureList->CreateNewKey();
  4642. pSubKey->SetString( "Name", tex.m_DebugName.String() );
  4643. pSubKey->SetString( "TexGroup", tex.m_TextureGroupName.String() );
  4644. pSubKey->SetInt( "Size", tex.GetMemUsage() );
  4645. if ( tex.GetCount() > 1 )
  4646. pSubKey->SetInt( "Count", tex.GetCount() );
  4647. pSubKey->SetString( "Format", ImageLoader::GetName( tex.GetImageFormat() ) );
  4648. pSubKey->SetInt( "Width", tex.GetWidth() );
  4649. pSubKey->SetInt( "Height", tex.GetHeight() );
  4650. pSubKey->SetInt( "BindsMax", tex.m_nTimesBoundMax );
  4651. pSubKey->SetInt( "BindsFrame", tex.m_nTimesBoundThisFrame );
  4652. }
  4653. D3DSURFACE_DESC desc;
  4654. m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT]->GetDesc( &desc );
  4655. AddBufferToTextureList( "BACKBUFFER", desc );
  4656. desc.MultiSampleType = D3DMULTISAMPLE_NONE; // front-buffer isn't multisampled
  4657. AddBufferToTextureList( "FRONTBUFFER", desc );
  4658. // ImageFormat imageFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
  4659. // if( imageFormat >= 0 )
  4660. {
  4661. VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_frame_" TEXTURE_GROUP_RENDER_TARGET,
  4662. COUNTER_GROUP_TEXTURE_PER_FRAME,
  4663. // ImageLoader::SizeInBytes( imageFormat ) * desc.Width * desc.Height );
  4664. 4 * desc.Width * desc.Height * ( 1 + MAX( 1, desc.MultiSampleType ) ) ); // hack (front-buffer (single-sampled) + back-buffer (multi-sampled) )
  4665. }
  4666. m_pZBufferSurface->GetDesc( &desc );
  4667. AddBufferToTextureList( "DEPTHBUFFER", desc );
  4668. // imageFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
  4669. // if( imageFormat >= 0 )
  4670. {
  4671. VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_frame_" TEXTURE_GROUP_RENDER_TARGET,
  4672. COUNTER_GROUP_TEXTURE_PER_FRAME,
  4673. // ImageLoader::SizeInBytes( imageFormat ) * desc.Width * desc.Height );
  4674. 4 * desc.Width * desc.Height * MAX( 1, desc.MultiSampleType ) ); // hack
  4675. }
  4676. if( m_pBackBufferSurfaces[BACK_BUFFER_INDEX_HDR] != NULL )
  4677. {
  4678. m_pBackBufferSurfaces[BACK_BUFFER_INDEX_HDR]->GetDesc( &desc );
  4679. AddBufferToTextureList( "HDR_BACKBUFFER", desc );
  4680. {
  4681. VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_frame_" TEXTURE_GROUP_RENDER_TARGET,
  4682. COUNTER_GROUP_TEXTURE_PER_FRAME,
  4683. 8 * desc.Width * desc.Height * MAX( 1, desc.MultiSampleType ) ); // hack
  4684. }
  4685. }
  4686. }
  4687. #if defined( _X360 )
  4688. // toggle to do one shot transmission
  4689. m_bEnableDebugTextureList = false;
  4690. int numTextures = m_Textures.Count() + 3;
  4691. xTextureList_t* pXTextureList = (xTextureList_t *)_alloca( numTextures * sizeof( xTextureList_t ) );
  4692. memset( pXTextureList, 0, numTextures * sizeof( xTextureList_t ) );
  4693. numTextures = 0;
  4694. for ( ShaderAPITextureHandle_t hTexture = m_Textures.Head() ; hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
  4695. {
  4696. Texture_t &tex = m_Textures[hTexture];
  4697. if ( !m_bDebugGetAllTextures && tex.m_LastBoundFrame != m_CurrentFrame )
  4698. {
  4699. continue;
  4700. }
  4701. if ( !( tex.m_Flags & Texture_t::IS_ALLOCATED ) )
  4702. {
  4703. continue;
  4704. }
  4705. IDirect3DBaseTexture *pD3DTexture = CShaderAPIDx8::GetD3DTexture( hTexture );
  4706. int refCount;
  4707. if ( tex.m_Flags & Texture_t::IS_DEPTH_STENCIL )
  4708. {
  4709. // interface forces us to ignore these
  4710. refCount = -1;
  4711. }
  4712. else
  4713. {
  4714. refCount = GetD3DTextureRefCount( pD3DTexture );
  4715. }
  4716. pXTextureList[numTextures].pName = tex.m_DebugName.String();
  4717. pXTextureList[numTextures].size = tex.m_SizeBytes * tex.m_NumCopies;
  4718. pXTextureList[numTextures].pGroupName = tex.m_TextureGroupName.String();
  4719. pXTextureList[numTextures].pFormatName = D3DFormatName( ImageLoader::ImageFormatToD3DFormat( tex.GetImageFormat() ) );
  4720. pXTextureList[numTextures].width = tex.GetWidth();
  4721. pXTextureList[numTextures].height = tex.GetHeight();
  4722. pXTextureList[numTextures].depth = tex.GetDepth();
  4723. pXTextureList[numTextures].numLevels = tex.m_NumLevels;
  4724. pXTextureList[numTextures].binds = tex.m_nTimesBoundThisFrame;
  4725. pXTextureList[numTextures].refCount = refCount;
  4726. pXTextureList[numTextures].edram = ( tex.m_Flags & Texture_t::IS_RENDER_TARGET_SURFACE ) != 0;
  4727. pXTextureList[numTextures].procedural = tex.m_NumCopies > 1;
  4728. pXTextureList[numTextures].final = ( tex.m_Flags & Texture_t::IS_FINALIZED ) != 0;
  4729. pXTextureList[numTextures].failed = ( tex.m_Flags & Texture_t::IS_ERROR_TEXTURE ) != 0;
  4730. pXTextureList[numTextures].pwl = ( tex.m_Flags & Texture_t::IS_PWL_CORRECTED ) != 0;
  4731. int reduced = 0;
  4732. if ( tex.m_CreationFlags & TEXTURE_CREATE_EXCLUDED )
  4733. {
  4734. reduced = 1;
  4735. }
  4736. else if ( tex.m_CreationFlags & TEXTURE_CREATE_REDUCED )
  4737. {
  4738. reduced = 2;
  4739. }
  4740. pXTextureList[numTextures].reduced = reduced;
  4741. cacheableState_e cacheableState = CS_STATIC;
  4742. int cacheableSize = 0;
  4743. if ( tex.m_Flags & Texture_t::IS_CACHEABLE )
  4744. {
  4745. if ( g_TextureHeap.IsTextureResident( pD3DTexture ) )
  4746. {
  4747. cacheableState = CS_VALID;
  4748. }
  4749. else
  4750. {
  4751. cacheableState = CS_EVICTED;
  4752. }
  4753. cacheableSize = g_TextureHeap.GetCacheableSize( pD3DTexture );
  4754. }
  4755. pXTextureList[numTextures].cacheableState = cacheableState;
  4756. pXTextureList[numTextures].cacheableSize = cacheableSize;
  4757. numTextures++;
  4758. }
  4759. // build special entries for implicit surfaces/textures
  4760. D3DSURFACE_DESC desc;
  4761. m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT]->GetDesc( &desc );
  4762. int size = ImageLoader::GetMemRequired(
  4763. desc.Width,
  4764. desc.Height,
  4765. 0,
  4766. ImageLoader::D3DFormatToImageFormat( desc.Format ),
  4767. false );
  4768. pXTextureList[numTextures].pName = "_rt_BackBuffer";
  4769. pXTextureList[numTextures].size = size;
  4770. pXTextureList[numTextures].pGroupName = TEXTURE_GROUP_RENDER_TARGET_SURFACE;
  4771. pXTextureList[numTextures].pFormatName = D3DFormatName( desc.Format );
  4772. pXTextureList[numTextures].width = desc.Width;
  4773. pXTextureList[numTextures].height = desc.Height;
  4774. pXTextureList[numTextures].depth = 1;
  4775. pXTextureList[numTextures].binds = 1;
  4776. pXTextureList[numTextures].refCount = 1;
  4777. pXTextureList[numTextures].sRGB = IS_D3DFORMAT_SRGB( desc.Format );
  4778. pXTextureList[numTextures].edram = true;
  4779. numTextures++;
  4780. m_pZBufferSurface->GetDesc( &desc );
  4781. pXTextureList[numTextures].pName = "_rt_DepthBuffer";
  4782. pXTextureList[numTextures].size = size;
  4783. pXTextureList[numTextures].pGroupName = TEXTURE_GROUP_RENDER_TARGET_SURFACE;
  4784. pXTextureList[numTextures].pFormatName = D3DFormatName( desc.Format );
  4785. pXTextureList[numTextures].width = desc.Width;
  4786. pXTextureList[numTextures].height = desc.Height;
  4787. pXTextureList[numTextures].depth = 1;
  4788. pXTextureList[numTextures].binds = 1;
  4789. pXTextureList[numTextures].refCount = 1;
  4790. pXTextureList[numTextures].sRGB = IS_D3DFORMAT_SRGB( desc.Format );
  4791. pXTextureList[numTextures].edram = true;
  4792. numTextures++;
  4793. // front buffer resides in DDR
  4794. pXTextureList[numTextures].pName = "_rt_FrontBuffer";
  4795. pXTextureList[numTextures].size = size;
  4796. pXTextureList[numTextures].pGroupName = TEXTURE_GROUP_RENDER_TARGET;
  4797. pXTextureList[numTextures].pFormatName = D3DFormatName( desc.Format );
  4798. pXTextureList[numTextures].width = desc.Width;
  4799. pXTextureList[numTextures].height = desc.Height;
  4800. pXTextureList[numTextures].depth = 1;
  4801. pXTextureList[numTextures].binds = 1;
  4802. pXTextureList[numTextures].refCount = 1;
  4803. pXTextureList[numTextures].sRGB = IS_D3DFORMAT_SRGB( desc.Format );
  4804. numTextures++;
  4805. int totalMemory = 0;
  4806. int cacheableMemory = 0;
  4807. for ( int i = 0; i < numTextures; i++ )
  4808. {
  4809. if ( pXTextureList[i].edram )
  4810. {
  4811. // skip edram based items
  4812. continue;
  4813. }
  4814. totalMemory += pXTextureList[i].size;
  4815. if ( pXTextureList[i].cacheableSize )
  4816. {
  4817. // don't accumulate the cacheable component
  4818. cacheableMemory += pXTextureList[i].cacheableSize;
  4819. }
  4820. }
  4821. Msg( "Total D3D Texture Memory: %.2f MB\n", (float)totalMemory/( 1024.0f * 1024.0f ) );
  4822. Msg( "Static D3D Texture Memory: %.2f MB\n", (float)(totalMemory - cacheableMemory)/( 1024.0f * 1024.0f ) );
  4823. Msg( "Dynamic D3D Texture Heap Memory: %.2f MB\n", (float)g_TextureHeap.GetCacheableHeapSize()/( 1024.0f * 1024.0f ) );
  4824. // transmit to console
  4825. XBX_rTextureList( numTextures, pXTextureList );
  4826. #endif
  4827. m_DebugTextureListLock.Unlock();
  4828. }
  4829. //-----------------------------------------------------------------------------
  4830. // Releases/reloads resources when other apps want some memory
  4831. //-----------------------------------------------------------------------------
  4832. void CShaderAPIDx8::ReleaseShaderObjects( bool bReleaseManagedResources /*= true*/ )
  4833. {
  4834. ReleaseInternalRenderTargets();
  4835. EvictManagedResourcesInternal();
  4836. // FIXME: Move into shaderdevice when textures move over.
  4837. #ifdef _DEBUG
  4838. // Helps to find the unreleased textures.
  4839. if ( TextureCount() > 0 && bReleaseManagedResources )
  4840. {
  4841. ShaderAPITextureHandle_t hTexture;
  4842. for ( hTexture = m_Textures.Head(); hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
  4843. {
  4844. if ( GetTexture( hTexture ).m_NumCopies == 1 )
  4845. {
  4846. if ( GetTexture( hTexture ).GetTexture() )
  4847. {
  4848. Warning( "Didn't correctly clean up texture 0x%8.8x (%s)\n", hTexture, GetTexture( hTexture ).m_DebugName.String() );
  4849. }
  4850. }
  4851. else
  4852. {
  4853. for ( int k = GetTexture( hTexture ).m_NumCopies; --k >= 0; )
  4854. {
  4855. if ( GetTexture( hTexture ).GetTexture( k ) != 0 )
  4856. {
  4857. Warning( "Didn't correctly clean up texture 0x%8.8x (%s)\n", hTexture, GetTexture( hTexture ).m_DebugName.String() );
  4858. break;
  4859. }
  4860. }
  4861. }
  4862. }
  4863. }
  4864. #endif
  4865. Assert( !bReleaseManagedResources || TextureCount() == 0 );
  4866. }
  4867. void CShaderAPIDx8::RestoreShaderObjects()
  4868. {
  4869. AcquireInternalRenderTargets();
  4870. SetRenderTarget();
  4871. }
  4872. #if defined( PIX_INSTRUMENTATION )
  4873. ConVar pix_break_on_event( "pix_break_on_event", "" );
  4874. #endif
  4875. //--------------------------------------------------------------------
  4876. // PIX instrumentation routines Windows only for now.
  4877. // Turn these on with PIX_INSTRUMENTATION in shaderdevicedx8.h
  4878. //--------------------------------------------------------------------
  4879. void CShaderAPIDx8::BeginPIXEvent( unsigned long color, const char* szName )
  4880. {
  4881. #if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) )
  4882. LOCK_SHADERAPI();
  4883. const char *p = pix_break_on_event.GetString();
  4884. if ( p && V_strlen( p ) )
  4885. {
  4886. if ( V_stristr( szName, p ) != NULL )
  4887. {
  4888. DebuggerBreak();
  4889. }
  4890. }
  4891. #if defined ( DX_TO_GL_ABSTRACTION )
  4892. GLMBeginPIXEvent( szName );
  4893. #if defined( _WIN32 )
  4894. // AMD PerfStudio integration: Call into D3D9.DLL's D3DPERF_BeginEvent() (this gets intercepted by PerfStudio even in GL mode).
  4895. if ( g_pShaderDeviceMgrDx8->m_pBeginEvent )
  4896. {
  4897. wchar_t wszName[128];
  4898. mbstowcs( wszName, szName, 128 );
  4899. g_pShaderDeviceMgrDx8->m_pBeginEvent( 0x2F2F2F2F, wszName );
  4900. }
  4901. #endif
  4902. #elif defined(_X360 )
  4903. char szPIXEventName[32];
  4904. PIXifyName( szPIXEventName, szName );
  4905. PIXBeginNamedEvent( color, szPIXEventName );
  4906. #else // PC
  4907. if ( PIXError() )
  4908. return;
  4909. wchar_t wszName[128];
  4910. mbstowcs( wszName, szName, 128 );
  4911. // Fire the PIX event, trapping for errors...
  4912. if ( D3DPERF_BeginEvent( color, wszName ) < 0 )
  4913. {
  4914. Warning( "PIX error Beginning %s event\n", szName );
  4915. IncrementPIXError();
  4916. }
  4917. #endif
  4918. #endif // #if defined( PIX_INSTRUMENTATION )
  4919. }
  4920. void CShaderAPIDx8::EndPIXEvent( void )
  4921. {
  4922. #if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) )
  4923. LOCK_SHADERAPI();
  4924. #ifdef _X360
  4925. PIXEndNamedEvent();
  4926. #elif defined( _PS3 )
  4927. #elif defined ( DX_TO_GL_ABSTRACTION )
  4928. GLMEndPIXEvent();
  4929. #if defined( _WIN32 )
  4930. // AMD PerfStudio integration: Call into D3D9.DLL's D3DPERF_EndEvent() (this gets intercepted by PerfStudio even in GL mode).
  4931. if ( g_pShaderDeviceMgrDx8->m_pEndEvent )
  4932. {
  4933. g_pShaderDeviceMgrDx8->m_pEndEvent();
  4934. }
  4935. #endif
  4936. #else // PC
  4937. if ( PIXError() )
  4938. return;
  4939. int nPIXReturnCode = D3DPERF_EndEvent();
  4940. #if !defined( NVPERFHUD )
  4941. // Fire the PIX event, trapping for errors...
  4942. if ( nPIXReturnCode < 0 )
  4943. {
  4944. Warning("PIX error ending event\n");
  4945. IncrementPIXError();
  4946. }
  4947. #endif
  4948. #endif
  4949. #endif // #if defined( PIX_INSTRUMENTATION )
  4950. }
  4951. void CShaderAPIDx8::AdvancePIXFrame()
  4952. {
  4953. #if defined( PIX_INSTRUMENTATION )
  4954. // Ping PIX when this bool goes from false to true
  4955. if ( r_pix_start.GetBool() && (!m_bPixCapturing) )
  4956. {
  4957. StartPIXInstrumentation();
  4958. m_bPixCapturing = true;
  4959. }
  4960. // If we want to record frames...
  4961. if ( r_pix_recordframes.GetInt() )
  4962. {
  4963. if ( m_nPixFrame == 0 ) // First frame to record
  4964. {
  4965. StartPIXInstrumentation();
  4966. m_nPixFrame++;
  4967. }
  4968. else if( m_nPixFrame == r_pix_recordframes.GetInt() ) // Last frame to record
  4969. {
  4970. EndPIXInstrumentation();
  4971. r_pix_recordframes.SetValue(0);
  4972. m_nPixFrame = 0;
  4973. }
  4974. else
  4975. {
  4976. m_nPixFrame++; // Recording frames...
  4977. }
  4978. }
  4979. #endif
  4980. }
  4981. // No begin-end for this...use this to put discrete markers in the PIX stream
  4982. void CShaderAPIDx8::SetPIXMarker( unsigned long color, const char* szName )
  4983. {
  4984. #if !defined( POSIX )
  4985. #if defined( PIX_INSTRUMENTATION )
  4986. LOCK_SHADERAPI();
  4987. #if defined( DX_TO_GL_ABSTRACTION )
  4988. if ( g_pShaderDeviceMgrDx8->m_pSetMarker )
  4989. {
  4990. wchar_t wszName[128];
  4991. mbstowcs(wszName, szName, 128 );
  4992. g_pShaderDeviceMgrDx8->m_pSetMarker( 0x2F2F2F2F, wszName );
  4993. }
  4994. #elif defined( _X360 )
  4995. #ifndef _DEBUG
  4996. char szPIXMarkerName[32];
  4997. PIXifyName( szPIXMarkerName, szName );
  4998. PIXSetMarker( color, szPIXMarkerName );
  4999. #endif
  5000. #else // PC
  5001. if ( PIXError() )
  5002. return;
  5003. wchar_t wszName[128];
  5004. mbstowcs(wszName, szName, 128 );
  5005. D3DPERF_SetMarker( color, wszName );
  5006. #endif
  5007. #endif // PIX_INSTRUMENTATION
  5008. #endif // not POSIX
  5009. }
  5010. void CShaderAPIDx8::StartPIXInstrumentation()
  5011. {
  5012. #if defined( PIX_INSTRUMENTATION )
  5013. SetPIXMarker( PIX_VALVE_ORANGE, "Valve_PIX_Capture_Start" );
  5014. #endif
  5015. }
  5016. void CShaderAPIDx8::EndPIXInstrumentation()
  5017. {
  5018. #if defined( PIX_INSTRUMENTATION )
  5019. SetPIXMarker( PIX_VALVE_ORANGE, "Valve_PIX_Capture_End" );
  5020. #endif
  5021. }
  5022. void CShaderAPIDx8::IncrementPIXError()
  5023. {
  5024. #if defined( PIX_INSTRUMENTATION ) && !defined( NVPERFHUD )
  5025. m_nPIXErrorCount++;
  5026. if ( m_nPIXErrorCount >= MAX_PIX_ERRORS )
  5027. {
  5028. Warning( "Source engine built with PIX instrumentation, but PIX doesn't seem to have been used to instantiate the game, which is necessary on PC.\n" );
  5029. }
  5030. #endif
  5031. }
  5032. // Have we already hit several PIX errors?
  5033. bool CShaderAPIDx8::PIXError()
  5034. {
  5035. #if defined( PIX_INSTRUMENTATION ) && !defined( NVPERFHUD )
  5036. return m_nPIXErrorCount >= MAX_PIX_ERRORS;
  5037. #else
  5038. return false;
  5039. #endif
  5040. }
  5041. //-----------------------------------------------------------------------------
  5042. // Check for device lost
  5043. //-----------------------------------------------------------------------------
  5044. void CShaderAPIDx8::ChangeVideoMode( const ShaderDeviceInfo_t &info )
  5045. {
  5046. if ( IsGameConsole() )
  5047. return;
  5048. LOCK_SHADERAPI();
  5049. m_PendingVideoModeChangeConfig = info;
  5050. m_bPendingVideoModeChange = true;
  5051. if ( info.m_DisplayMode.m_nWidth != 0 && info.m_DisplayMode.m_nHeight != 0 )
  5052. {
  5053. m_nWindowWidth = info.m_DisplayMode.m_nWidth;
  5054. m_nWindowHeight = info.m_DisplayMode.m_nHeight;
  5055. }
  5056. }
  5057. //-----------------------------------------------------------------------------
  5058. // Compute fill rate
  5059. //-----------------------------------------------------------------------------
  5060. void CShaderAPIDx8::ComputeFillRate()
  5061. {
  5062. if ( IsGameConsole() )
  5063. {
  5064. // not valid
  5065. return;
  5066. }
  5067. static unsigned char* pBuf = 0;
  5068. int width, height;
  5069. GetWindowSize( width, height );
  5070. // Snapshot; look at total # pixels drawn...
  5071. if ( !pBuf )
  5072. {
  5073. int memSize = ShaderUtil()->GetMemRequired(
  5074. width,
  5075. height,
  5076. 1,
  5077. IMAGE_FORMAT_RGB888,
  5078. false ) + 4;
  5079. pBuf = (unsigned char*)malloc( memSize );
  5080. }
  5081. ReadPixels(
  5082. 0,
  5083. 0,
  5084. width,
  5085. height,
  5086. pBuf,
  5087. IMAGE_FORMAT_RGB888 );
  5088. int mask = 0xFF;
  5089. int count = 0;
  5090. unsigned char* pRead = pBuf;
  5091. for (int i = 0; i < height; ++i)
  5092. {
  5093. for (int j = 0; j < width; ++j)
  5094. {
  5095. int val = *(int*)pRead;
  5096. count += (val & mask);
  5097. pRead += 3;
  5098. }
  5099. }
  5100. }
  5101. //-----------------------------------------------------------------------------
  5102. // Use this to get the mesh builder that allows us to modify vertex data
  5103. //-----------------------------------------------------------------------------
  5104. bool CShaderAPIDx8::InFlashlightMode() const
  5105. {
  5106. return ShaderUtil()->InFlashlightMode();
  5107. }
  5108. bool CShaderAPIDx8::IsCascadedShadowMapping() const
  5109. {
  5110. return ShaderUtil()->IsCascadedShadowMapping();
  5111. }
  5112. void CShaderAPIDx8::SetCascadedShadowMappingState( const CascadedShadowMappingState_t &state, ITexture *pDepthTextureAtlas )
  5113. {
  5114. LOCK_SHADERAPI();
  5115. m_CascadedShadowMappingState = state;
  5116. m_CascadedShadowMappingState_LightMapScaled = state;
  5117. // save some PS instructions by pre-multiplying by (1/lightmapScale)
  5118. m_CascadedShadowMappingState_LightMapScaled.m_vLightColor.x *= m_CascadedShadowMappingState_LightMapScaled.m_vLightColor.w;
  5119. m_CascadedShadowMappingState_LightMapScaled.m_vLightColor.y *= m_CascadedShadowMappingState_LightMapScaled.m_vLightColor.w;
  5120. m_CascadedShadowMappingState_LightMapScaled.m_vLightColor.z *= m_CascadedShadowMappingState_LightMapScaled.m_vLightColor.w;
  5121. m_pCascadedShadowMappingDepthTexture = pDepthTextureAtlas;
  5122. }
  5123. const CascadedShadowMappingState_t &CShaderAPIDx8::GetCascadedShadowMappingState( ITexture **pDepthTextureAtlas, bool bLightMapScale ) const
  5124. {
  5125. if ( pDepthTextureAtlas )
  5126. *pDepthTextureAtlas = m_pCascadedShadowMappingDepthTexture;
  5127. if ( bLightMapScale )
  5128. {
  5129. return m_CascadedShadowMappingState_LightMapScaled;
  5130. }
  5131. else
  5132. {
  5133. return m_CascadedShadowMappingState;
  5134. }
  5135. }
  5136. bool CShaderAPIDx8::IsRenderingPaint() const
  5137. {
  5138. return ShaderUtil()->IsRenderingPaint();
  5139. }
  5140. bool CShaderAPIDx8::InEditorMode() const
  5141. {
  5142. return ShaderUtil()->InEditorMode();
  5143. }
  5144. //-----------------------------------------------------------------------------
  5145. // returns the current time in seconds...
  5146. //-----------------------------------------------------------------------------
  5147. double CShaderAPIDx8::CurrentTime() const
  5148. {
  5149. return m_flCurrGameTime;
  5150. }
  5151. //-----------------------------------------------------------------------------
  5152. // Updates the depth bias
  5153. //-----------------------------------------------------------------------------
  5154. static void OnDepthBiasChanged( IConVar *var, const char *pOldValue, float flOldValue )
  5155. {
  5156. g_ShaderAPIDX8.UpdateDepthBiasState();
  5157. }
  5158. #ifdef OSX
  5159. static ConVar mat_slopescaledepthbias_decal( "mat_slopescaledepthbias_decal", "-4", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "", OnDepthBiasChanged );
  5160. static ConVar mat_depthbias_decal( "mat_depthbias_decal", "-0.25", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "", OnDepthBiasChanged );
  5161. static ConVar mat_slopescaledepthbias_normal( "mat_slopescaledepthbias_normal", "0.0f", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "", OnDepthBiasChanged );
  5162. static ConVar mat_depthbias_normal( "mat_depthbias_normal", "0.0f", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "", OnDepthBiasChanged );
  5163. #else
  5164. static ConVar mat_slopescaledepthbias_decal( "mat_slopescaledepthbias_decal", "-2", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "", OnDepthBiasChanged );
  5165. static ConVar mat_depthbias_decal( "mat_depthbias_decal", "-0.0000038", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "", OnDepthBiasChanged );
  5166. static ConVar mat_slopescaledepthbias_normal( "mat_slopescaledepthbias_normal", "0.0f", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "", OnDepthBiasChanged );
  5167. static ConVar mat_depthbias_normal( "mat_depthbias_normal", "0.0f", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "", OnDepthBiasChanged );
  5168. #endif
  5169. void CShaderAPIDx8::UpdateDepthBiasState()
  5170. {
  5171. m_ZBias.m_flOOSlopeScaleDepthBias = mat_slopescaledepthbias_normal.GetFloat();
  5172. m_ZBias.m_flOODepthBias = mat_depthbias_normal.GetFloat();
  5173. m_ZBiasDecal.m_flOOSlopeScaleDepthBias = mat_slopescaledepthbias_decal.GetFloat();
  5174. m_ZBiasDecal.m_flOODepthBias = mat_depthbias_decal.GetFloat();
  5175. }
  5176. //-----------------------------------------------------------------------------
  5177. // Methods called by the transition table that use dynamic state...
  5178. //-----------------------------------------------------------------------------
  5179. void CShaderAPIDx8::ApplyZBias( const DepthTestState_t& shaderState )
  5180. {
  5181. // PORTAL 2 hack: Disable slope scale z bias for decals if we have a poly offset matrix set. This avoids decals and overlays rendering
  5182. // on top of other stuff through portal views on the PS3.
  5183. float a = m_DynamicState.m_FastClipEnabled ? 0.0f : m_ZBiasDecal.m_flOOSlopeScaleDepthBias;
  5184. float b = m_ZBias.m_flOOSlopeScaleDepthBias;
  5185. float c = m_ZBiasDecal.m_flOODepthBias;
  5186. float d = m_ZBias.m_flOODepthBias;
  5187. // bias = (s * D3DRS_SLOPESCALEDEPTHBIAS) + D3DRS_DEPTHBIAS, where s is the maximum depth slope of the triangle being rendered
  5188. if ( g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported )
  5189. {
  5190. float fSlopeScaleDepthBias, fDepthBias;
  5191. if ( shaderState.m_ZBias == SHADER_POLYOFFSET_DECAL )
  5192. {
  5193. fSlopeScaleDepthBias = a;
  5194. fDepthBias = c;
  5195. }
  5196. else if ( shaderState.m_ZBias == SHADER_POLYOFFSET_SHADOW_BIAS )
  5197. {
  5198. fSlopeScaleDepthBias = m_fShadowSlopeScaleDepthBias;
  5199. fDepthBias = m_fShadowDepthBias;
  5200. m_TransitionTable.SetShadowDepthBiasValuesDirty( false );
  5201. }
  5202. else // assume SHADER_POLYOFFSET_DISABLE
  5203. {
  5204. fSlopeScaleDepthBias = b;
  5205. fDepthBias = d;
  5206. }
  5207. if( ReverseDepthOnX360() )
  5208. {
  5209. fSlopeScaleDepthBias = -fSlopeScaleDepthBias;
  5210. fDepthBias = -fDepthBias;
  5211. }
  5212. SetRenderState( D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*) (&fSlopeScaleDepthBias)) );
  5213. SetRenderState( D3DRS_DEPTHBIAS, *((DWORD*) (&fDepthBias)) );
  5214. }
  5215. else
  5216. {
  5217. MarkAllUserClipPlanesDirty();
  5218. m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |= STATE_CHANGED;
  5219. }
  5220. }
  5221. //-----------------------------------------------------------------------------
  5222. // Used to clear the transition table when we know it's become invalid.
  5223. //-----------------------------------------------------------------------------
  5224. void CShaderAPIDx8::ClearSnapshots()
  5225. {
  5226. LOCK_SHADERAPI();
  5227. m_TransitionTable.Reset();
  5228. InitRenderState();
  5229. }
  5230. static void KillTranslation( D3DXMATRIX& mat )
  5231. {
  5232. mat[3] = 0.0f;
  5233. mat[7] = 0.0f;
  5234. mat[11] = 0.0f;
  5235. mat[12] = 0.0f;
  5236. mat[13] = 0.0f;
  5237. mat[14] = 0.0f;
  5238. mat[15] = 1.0f;
  5239. }
  5240. static void PrintMatrix( const char *name, const D3DXMATRIX& mat )
  5241. {
  5242. int row, col;
  5243. char buf[128];
  5244. Plat_DebugString( name );
  5245. Plat_DebugString( "\n" );
  5246. for( row = 0; row < 4; row++ )
  5247. {
  5248. Plat_DebugString( " " );
  5249. for( col = 0; col < 4; col++ )
  5250. {
  5251. sprintf( buf, "%f ", ( float )mat( row, col ) );
  5252. Plat_DebugString( buf );
  5253. }
  5254. Plat_DebugString( "\n" );
  5255. }
  5256. Plat_DebugString( "\n" );
  5257. }
  5258. //-----------------------------------------------------------------------------
  5259. // Gets the vertex format for a particular snapshot id
  5260. //-----------------------------------------------------------------------------
  5261. VertexFormat_t CShaderAPIDx8::ComputeVertexUsage( int num, StateSnapshot_t* pIds ) const
  5262. {
  5263. LOCK_SHADERAPI();
  5264. if (num == 0)
  5265. return 0;
  5266. // We don't have to all sorts of crazy stuff if there's only one snapshot
  5267. if ( num == 1 )
  5268. {
  5269. const ShadowShaderState_t& state = m_TransitionTable.GetSnapshotShader( pIds[0] );
  5270. return state.m_VertexUsage;
  5271. }
  5272. Assert( pIds );
  5273. // Aggregating vertex formats is a little tricky;
  5274. // For example, what do we do when two passes want user data?
  5275. // Can we assume they are the same? For now, I'm going to
  5276. // just print a warning in debug.
  5277. VertexCompressionType_t compression = VERTEX_COMPRESSION_INVALID;
  5278. int userDataSize = 0;
  5279. int numBones = 0;
  5280. int texCoordSize[VERTEX_MAX_TEXTURE_COORDINATES] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  5281. int flags = 0;
  5282. for (int i = num; --i >= 0; )
  5283. {
  5284. const ShadowShaderState_t& state = m_TransitionTable.GetSnapshotShader( pIds[i] );
  5285. VertexFormat_t fmt = state.m_VertexUsage;
  5286. flags |= VertexFlags(fmt);
  5287. VertexCompressionType_t newCompression = CompressionType( fmt );
  5288. if ( ( compression != newCompression ) && ( compression != VERTEX_COMPRESSION_INVALID ) )
  5289. {
  5290. Warning("Encountered a material with two passes that specify different vertex compression types!\n");
  5291. compression = VERTEX_COMPRESSION_NONE; // Be safe, disable compression
  5292. }
  5293. int newNumBones = NumBoneWeights(fmt);
  5294. if ((numBones != newNumBones) && (newNumBones != 0))
  5295. {
  5296. if (numBones != 0)
  5297. {
  5298. Warning("Encountered a material with two passes that use different numbers of bones!\n");
  5299. }
  5300. numBones = newNumBones;
  5301. }
  5302. int newUserSize = UserDataSize(fmt);
  5303. if ((userDataSize != newUserSize) && (newUserSize != 0))
  5304. {
  5305. if (userDataSize != 0)
  5306. {
  5307. Warning("Encountered a material with two passes that use different user data sizes!\n");
  5308. }
  5309. userDataSize = newUserSize;
  5310. }
  5311. for ( int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j )
  5312. {
  5313. int newSize = TexCoordSize( j, fmt );
  5314. if ( ( texCoordSize[j] != newSize ) && ( newSize != 0 ) )
  5315. {
  5316. if ( texCoordSize[j] != 0 )
  5317. {
  5318. Warning("Encountered a material with two passes that use different texture coord sizes!\n");
  5319. }
  5320. if ( texCoordSize[j] < newSize )
  5321. {
  5322. texCoordSize[j] = newSize;
  5323. }
  5324. }
  5325. }
  5326. }
  5327. return MeshMgr()->ComputeVertexFormat( flags, VERTEX_MAX_TEXTURE_COORDINATES,
  5328. texCoordSize, numBones, userDataSize );
  5329. }
  5330. VertexFormat_t CShaderAPIDx8::ComputeVertexFormat( int num, StateSnapshot_t* pIds ) const
  5331. {
  5332. LOCK_SHADERAPI();
  5333. VertexFormat_t fmt = ComputeVertexUsage( num, pIds );
  5334. return fmt;
  5335. }
  5336. //-----------------------------------------------------------------------------
  5337. // Commits a range of vertex shader constants
  5338. //-----------------------------------------------------------------------------
  5339. static void CommitVertexShaderConstantRange( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState,
  5340. DynamicState_t &currentState, bool bForce, int nFirstConstant, int nCount )
  5341. {
  5342. if ( IsX360() )
  5343. {
  5344. // invalid code path for 360, not coded for 360 GPU constant awareness
  5345. Assert( 0 );
  5346. return;
  5347. }
  5348. int nFirstCommit = nFirstConstant;
  5349. int nCommitCount = 0;
  5350. for ( int i = 0; i < nCount; ++i )
  5351. {
  5352. int nVar = nFirstConstant + i;
  5353. bool bDifferentValue = bForce || ( desiredState.m_pVectorVertexShaderConstant[nVar] != currentState.m_pVectorVertexShaderConstant[nVar] );
  5354. if ( !bDifferentValue )
  5355. {
  5356. if ( nCommitCount != 0 )
  5357. {
  5358. // flush the prior range
  5359. pDevice->SetVertexShaderConstantF( nFirstCommit, desiredState.m_pVectorVertexShaderConstant[nFirstCommit].Base(), nCommitCount );
  5360. memcpy( &currentState.m_pVectorVertexShaderConstant[nFirstCommit],
  5361. &desiredState.m_pVectorVertexShaderConstant[nFirstCommit], nCommitCount * 4 * sizeof(float) );
  5362. }
  5363. // start of new range
  5364. nFirstCommit = nVar + 1;
  5365. nCommitCount = 0;
  5366. }
  5367. else
  5368. {
  5369. ++nCommitCount;
  5370. }
  5371. }
  5372. if ( nCommitCount != 0 )
  5373. {
  5374. // flush range
  5375. pDevice->SetVertexShaderConstantF( nFirstCommit, desiredState.m_pVectorVertexShaderConstant[nFirstCommit].Base(), nCommitCount );
  5376. memcpy( &currentState.m_pVectorVertexShaderConstant[nFirstCommit],
  5377. &desiredState.m_pVectorVertexShaderConstant[nFirstCommit], nCommitCount * 4 * sizeof(float) );
  5378. }
  5379. }
  5380. //-----------------------------------------------------------------------------
  5381. // Gets the current buffered state... (debug only)
  5382. //-----------------------------------------------------------------------------
  5383. void CShaderAPIDx8::GetBufferedState( BufferedState_t& state )
  5384. {
  5385. memcpy( &state.m_Transform[0], &GetTransform(MATERIAL_MODEL), sizeof(D3DXMATRIX) );
  5386. memcpy( &state.m_Transform[1], &GetTransform(MATERIAL_VIEW), sizeof(D3DXMATRIX) );
  5387. memcpy( &state.m_Transform[2], &GetTransform(MATERIAL_PROJECTION), sizeof(D3DXMATRIX) );
  5388. memcpy( &state.m_Viewport, &m_DynamicState.m_Viewport, sizeof(state.m_Viewport) );
  5389. state.m_PixelShader = ShaderManager()->GetCurrentPixelShader();
  5390. state.m_VertexShader = ShaderManager()->GetCurrentVertexShader();
  5391. for (int i = 0; i < g_pHardwareConfig->GetSamplerCount(); ++i)
  5392. {
  5393. state.m_BoundTexture[i] = m_DynamicState.m_SamplerState[i].m_BoundTexture;
  5394. }
  5395. }
  5396. //-----------------------------------------------------------------------------
  5397. // The shade mode
  5398. //-----------------------------------------------------------------------------
  5399. void CShaderAPIDx8::ShadeMode( ShaderShadeMode_t mode )
  5400. {
  5401. LOCK_SHADERAPI();
  5402. D3DSHADEMODE shadeMode = (mode == SHADER_FLAT) ? D3DSHADE_FLAT : D3DSHADE_GOURAUD;
  5403. if (m_DynamicState.m_ShadeMode != shadeMode)
  5404. {
  5405. m_DynamicState.m_ShadeMode = shadeMode;
  5406. SetSupportedRenderState( D3DRS_SHADEMODE, shadeMode );
  5407. }
  5408. }
  5409. //-----------------------------------------------------------------------------
  5410. // Buffering 2 frames ahead
  5411. //-----------------------------------------------------------------------------
  5412. void CShaderAPIDx8::EnableBuffer2FramesAhead( bool bEnable )
  5413. {
  5414. #ifdef _X360
  5415. m_bBuffer2FramesAhead = bEnable;
  5416. if ( bEnable != m_DynamicState.m_bBuffer2Frames )
  5417. {
  5418. SetRenderState( D3DRS_BUFFER2FRAMES, bEnable );
  5419. m_DynamicState.m_bBuffer2Frames = bEnable;
  5420. }
  5421. #endif
  5422. }
  5423. void CShaderAPIDx8::GetActualProjectionMatrix( float *pMatrix )
  5424. {
  5425. memcpy( pMatrix, &GetProjectionMatrix(), sizeof( D3DMATRIX ) );
  5426. }
  5427. //-----------------------------------------------------------------------------
  5428. //
  5429. // note this duplicates some constants for VS too (helps optimize away some PS ops for shaders that take advantage of it - currently only spritecard)
  5430. // PS: sets c13, c14, iConstant
  5431. // VS: sets c12, c13
  5432. //
  5433. //-----------------------------------------------------------------------------
  5434. void CShaderAPIDx8::SetDepthFeatheringShaderConstants( int iConstant, float fDepthBlendScale )
  5435. {
  5436. float fConstantValues[4];
  5437. fConstantValues[0] = 50.0f / fDepthBlendScale;
  5438. // The old depth feathering shader code worked in proj. space, which wasn't a sane place to compute depth feathering on PS3 through portals
  5439. // (because we use an oblique projection on PS3 to simulate user clip planes). The new methods computes depth feathering in viewspace, so
  5440. // we need to convert fDepthBlendScale to something which looks reasonable vs. the computing the depth blend in proj. space.
  5441. const float flDepthFeatherFudgeFactor = 1.5f;
  5442. fConstantValues[1] = flDepthFeatherFudgeFactor * fDepthBlendScale;
  5443. fConstantValues[2] = flDepthFeatherFudgeFactor / fDepthBlendScale;
  5444. fConstantValues[3] = 0.0f;
  5445. VMatrix projToViewMatrix;
  5446. MatrixInverseGeneral( *reinterpret_cast< const VMatrix * >( &GetProjectionMatrix() ), projToViewMatrix );
  5447. projToViewMatrix = projToViewMatrix.Transpose();
  5448. // Send down rows 2 (Z) and 3 (W), because that's all the shader needs to recover worldspace Z.
  5449. SetPixelShaderConstantInternal( DEPTH_FEATHER_PROJ_TO_VIEW_Z, &projToViewMatrix.m[2][0], 2 );
  5450. // same for VS
  5451. SetVertexShaderConstantInternal( VERTEX_SHADER_SHADER_SPECIFIC_CONST_12, &projToViewMatrix.m[2][0], 2 );
  5452. SetPixelShaderConstantInternal( iConstant, fConstantValues );
  5453. }
  5454. void CShaderAPIDx8::FlipCulling( bool bFlipCulling )
  5455. {
  5456. if ( bFlipCulling != m_bFlipCulling )
  5457. {
  5458. m_bFlipCulling = bFlipCulling;
  5459. D3DCULL nCullMode = m_DynamicState.m_CullMode;
  5460. if ( m_bFlipCulling )
  5461. {
  5462. if ( nCullMode != D3DCULL_NONE )
  5463. {
  5464. nCullMode = ( nCullMode == D3DCULL_CW ) ? D3DCULL_CCW : D3DCULL_CW;
  5465. }
  5466. }
  5467. SetRenderState( D3DRS_CULLMODE, nCullMode );
  5468. }
  5469. }
  5470. //-----------------------------------------------------------------------------
  5471. // Cull mode..
  5472. //-----------------------------------------------------------------------------
  5473. void CShaderAPIDx8::SetCullModeState( bool bEnable, D3DCULL nDesiredCullMode )
  5474. {
  5475. nDesiredCullMode = bEnable ? nDesiredCullMode : D3DCULL_NONE;
  5476. if ( nDesiredCullMode != m_DynamicState.m_CullMode )
  5477. {
  5478. D3DCULL nCullMode = nDesiredCullMode;
  5479. if ( m_bFlipCulling )
  5480. {
  5481. if ( nCullMode != D3DCULL_NONE )
  5482. {
  5483. nCullMode = ( nCullMode == D3DCULL_CW ) ? D3DCULL_CCW : D3DCULL_CW;
  5484. }
  5485. }
  5486. SetRenderState( D3DRS_CULLMODE, nCullMode );
  5487. m_DynamicState.m_CullMode = nDesiredCullMode;
  5488. }
  5489. }
  5490. void CShaderAPIDx8::ApplyCullEnable( bool bEnable )
  5491. {
  5492. m_DynamicState.m_bCullEnabled = bEnable;
  5493. /*
  5494. int nCullOverride = GetIntRenderingParameter( INT_RENDERPARM_CULL_OVERRIDE );
  5495. if ( nCullOverride == RENDER_PARM_CULL_MODE_OVERRIDE_CW )
  5496. {
  5497. m_DynamicState.m_DesiredCullMode = D3DCULL_CW;
  5498. m_DynamicState.m_bCullEnabled = true;
  5499. }
  5500. else if ( nCullOverride == RENDER_PARM_CULL_MODE_OVERRIDE_CCW )
  5501. {
  5502. m_DynamicState.m_DesiredCullMode = D3DCULL_CCW;
  5503. m_DynamicState.m_bCullEnabled = true;
  5504. }
  5505. */
  5506. SetCullModeState( m_DynamicState.m_bCullEnabled, m_DynamicState.m_DesiredCullMode );
  5507. }
  5508. void CShaderAPIDx8::CullMode( MaterialCullMode_t nCullMode )
  5509. {
  5510. LOCK_SHADERAPI();
  5511. D3DCULL nNewCullMode;
  5512. switch( nCullMode )
  5513. {
  5514. case MATERIAL_CULLMODE_CCW:
  5515. nNewCullMode = D3DCULL_CCW; // Culls back-facing polygons (default)
  5516. break;
  5517. case MATERIAL_CULLMODE_CW:
  5518. nNewCullMode = D3DCULL_CW; // Culls front-facing polygons
  5519. break;
  5520. case MATERIAL_CULLMODE_NONE:
  5521. nNewCullMode = D3DCULL_NONE; // Culls nothing
  5522. break;
  5523. default:
  5524. Warning( "CullMode: invalid cullMode\n" );
  5525. return;
  5526. }
  5527. if ( m_DynamicState.m_DesiredCullMode != nNewCullMode )
  5528. {
  5529. m_DynamicState.m_DesiredCullMode = nNewCullMode;
  5530. SetCullModeState( m_DynamicState.m_bCullEnabled, m_DynamicState.m_DesiredCullMode );
  5531. }
  5532. }
  5533. void CShaderAPIDx8::FlipCullMode( void )
  5534. {
  5535. LOCK_SHADERAPI();
  5536. switch( m_DynamicState.m_DesiredCullMode )
  5537. {
  5538. case D3DCULL_CCW:
  5539. m_DynamicState.m_DesiredCullMode = D3DCULL_CW;
  5540. break;
  5541. case D3DCULL_CW:
  5542. m_DynamicState.m_DesiredCullMode = D3DCULL_CCW;
  5543. break;
  5544. case D3DCULL_NONE:
  5545. m_DynamicState.m_DesiredCullMode = D3DCULL_NONE;
  5546. break;
  5547. default:
  5548. Warning( "FlipCullMode: invalid cullMode\n" );
  5549. return;
  5550. }
  5551. SetCullModeState( m_DynamicState.m_bCullEnabled, m_DynamicState.m_DesiredCullMode );
  5552. }
  5553. static ConVar mat_alphacoverage( "mat_alphacoverage", IsX360() ? "0" : "1", FCVAR_DEVELOPMENTONLY );
  5554. void CShaderAPIDx8::ApplyAlphaToCoverage( bool bEnable )
  5555. {
  5556. if ( mat_alphacoverage.GetBool() )
  5557. {
  5558. if ( bEnable )
  5559. EnableAlphaToCoverage();
  5560. else
  5561. DisableAlphaToCoverage();
  5562. }
  5563. else
  5564. {
  5565. DisableAlphaToCoverage();
  5566. }
  5567. }
  5568. //-----------------------------------------------------------------------------
  5569. // Returns the current cull mode of the current material (for selection mode only)
  5570. //-----------------------------------------------------------------------------
  5571. D3DCULL CShaderAPIDx8::GetCullMode() const
  5572. {
  5573. Assert( m_pMaterial );
  5574. if ( m_pMaterial->GetMaterialVarFlag( MATERIAL_VAR_NOCULL ) )
  5575. return D3DCULL_NONE;
  5576. return m_DynamicState.m_DesiredCullMode;
  5577. }
  5578. void CShaderAPIDx8::SetRasterState( const ShaderRasterState_t& state )
  5579. {
  5580. // FIXME: Implement!
  5581. }
  5582. void CShaderAPIDx8::ForceDepthFuncEquals( bool bEnable )
  5583. {
  5584. LOCK_SHADERAPI();
  5585. if ( !g_pShaderDeviceDx8->IsDeactivated() )
  5586. {
  5587. m_TransitionTable.ForceDepthFuncEquals( bEnable );
  5588. }
  5589. }
  5590. void CShaderAPIDx8::OverrideDepthEnable( bool bEnable, bool bDepthWriteEnable, bool bDepthTestEnable )
  5591. {
  5592. LOCK_SHADERAPI();
  5593. if ( !g_pShaderDeviceDx8->IsDeactivated() )
  5594. {
  5595. m_TransitionTable.OverrideDepthEnable( bEnable, bDepthWriteEnable, bDepthTestEnable );
  5596. }
  5597. }
  5598. void CShaderAPIDx8::OverrideAlphaWriteEnable( bool bOverrideEnable, bool bAlphaWriteEnable )
  5599. {
  5600. LOCK_SHADERAPI();
  5601. if ( !g_pShaderDeviceDx8->IsDeactivated() )
  5602. {
  5603. m_TransitionTable.OverrideAlphaWriteEnable( bOverrideEnable, bAlphaWriteEnable );
  5604. }
  5605. }
  5606. void CShaderAPIDx8::OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable )
  5607. {
  5608. LOCK_SHADERAPI();
  5609. if ( !g_pShaderDeviceDx8->IsDeactivated() )
  5610. {
  5611. m_TransitionTable.OverrideColorWriteEnable( bOverrideEnable, bColorWriteEnable );
  5612. }
  5613. }
  5614. void CShaderAPIDx8::UpdateFastClipUserClipPlane( void )
  5615. {
  5616. float plane[4];
  5617. switch( m_DynamicState.m_HeightClipMode )
  5618. {
  5619. case MATERIAL_HEIGHTCLIPMODE_DISABLE:
  5620. EnableFastClip( false );
  5621. break;
  5622. case MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT:
  5623. plane[0] = 0.0f;
  5624. plane[1] = 0.0f;
  5625. plane[2] = 1.0f;
  5626. plane[3] = m_DynamicState.m_HeightClipZ;
  5627. EnableFastClip( true );
  5628. SetFastClipPlane(plane);
  5629. break;
  5630. case MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT:
  5631. plane[0] = 0.0f;
  5632. plane[1] = 0.0f;
  5633. plane[2] = -1.0f;
  5634. plane[3] = -m_DynamicState.m_HeightClipZ;
  5635. EnableFastClip( true );
  5636. SetFastClipPlane(plane);
  5637. break;
  5638. }
  5639. }
  5640. void CShaderAPIDx8::SetHeightClipZ( float z )
  5641. {
  5642. LOCK_SHADERAPI();
  5643. if( z != m_DynamicState.m_HeightClipZ )
  5644. {
  5645. m_DynamicState.m_HeightClipZ = z;
  5646. UpdateVertexShaderFogParams();
  5647. UpdateFastClipUserClipPlane();
  5648. m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |= STATE_CHANGED;
  5649. }
  5650. }
  5651. void CShaderAPIDx8::SetHeightClipMode( MaterialHeightClipMode_t heightClipMode )
  5652. {
  5653. LOCK_SHADERAPI();
  5654. if( heightClipMode != m_DynamicState.m_HeightClipMode )
  5655. {
  5656. m_DynamicState.m_HeightClipMode = heightClipMode;
  5657. UpdateVertexShaderFogParams();
  5658. UpdateFastClipUserClipPlane();
  5659. m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |= STATE_CHANGED;
  5660. }
  5661. }
  5662. void CShaderAPIDx8::SetClipPlane( int index, const float *pPlane )
  5663. {
  5664. LOCK_SHADERAPI();
  5665. Assert( index < g_pHardwareConfig->MaxUserClipPlanes() && index >= 0 );
  5666. // NOTE: The plane here is specified in *world space*
  5667. // NOTE: This is done because they assume Ax+By+Cz+Dw = 0 (where w = 1 in real space)
  5668. // while we use Ax+By+Cz=D
  5669. D3DXPLANE plane;
  5670. plane.a = pPlane[0];
  5671. plane.b = pPlane[1];
  5672. plane.c = pPlane[2];
  5673. plane.d = -pPlane[3];
  5674. if ( plane != m_DynamicState.m_UserClipPlaneWorld[index] )
  5675. {
  5676. m_DynamicState.m_UserClipPlaneChanged |= ( 1 << index );
  5677. m_DynamicState.m_UserClipPlaneWorld[index] = plane;
  5678. }
  5679. }
  5680. //-----------------------------------------------------------------------------
  5681. // Converts a D3DXMatrix to a VMatrix and back
  5682. //-----------------------------------------------------------------------------
  5683. void CShaderAPIDx8::D3DXMatrixToVMatrix( const D3DXMATRIX &in, VMatrix &out )
  5684. {
  5685. MatrixTranspose( *(const VMatrix*)&in, out );
  5686. }
  5687. void CShaderAPIDx8::VMatrixToD3DXMatrix( const VMatrix &in, D3DXMATRIX &out )
  5688. {
  5689. MatrixTranspose( in, *(VMatrix*)&out );
  5690. }
  5691. //-----------------------------------------------------------------------------
  5692. // Mark all user clip planes as being dirty
  5693. //-----------------------------------------------------------------------------
  5694. void CShaderAPIDx8::MarkAllUserClipPlanesDirty()
  5695. {
  5696. m_DynamicState.m_UserClipPlaneChanged |= ( 1 << g_pHardwareConfig->MaxUserClipPlanes() ) - 1;
  5697. m_DynamicState.m_bFastClipPlaneChanged = true;
  5698. }
  5699. //-----------------------------------------------------------------------------
  5700. // User clip plane override
  5701. //-----------------------------------------------------------------------------
  5702. void CShaderAPIDx8::EnableUserClipTransformOverride( bool bEnable )
  5703. {
  5704. LOCK_SHADERAPI();
  5705. if ( m_DynamicState.m_bUserClipTransformOverride != bEnable )
  5706. {
  5707. m_DynamicState.m_bUserClipTransformOverride = bEnable;
  5708. MarkAllUserClipPlanesDirty();
  5709. }
  5710. }
  5711. //-----------------------------------------------------------------------------
  5712. // Specify user clip transform
  5713. //-----------------------------------------------------------------------------
  5714. void CShaderAPIDx8::UserClipTransform( const VMatrix &worldToProjection )
  5715. {
  5716. LOCK_SHADERAPI();
  5717. D3DXMATRIX dxWorldToProjection;
  5718. VMatrixToD3DXMatrix( worldToProjection, dxWorldToProjection );
  5719. if ( m_DynamicState.m_UserClipTransform != dxWorldToProjection )
  5720. {
  5721. m_DynamicState.m_UserClipTransform = dxWorldToProjection;
  5722. if ( m_DynamicState.m_bUserClipTransformOverride )
  5723. {
  5724. MarkAllUserClipPlanesDirty();
  5725. }
  5726. }
  5727. }
  5728. //-----------------------------------------------------------------------------
  5729. // Enables a user clip plane
  5730. //-----------------------------------------------------------------------------
  5731. void CShaderAPIDx8::EnableClipPlane( int index, bool bEnable )
  5732. {
  5733. LOCK_SHADERAPI();
  5734. Assert( index < g_pHardwareConfig->MaxUserClipPlanes() && index >= 0 );
  5735. if( ( m_DynamicState.m_UserClipPlaneEnabled & ( 1 << index ) ? true : false ) != bEnable )
  5736. {
  5737. if ( bEnable )
  5738. {
  5739. m_DynamicState.m_UserClipPlaneEnabled |= ( 1 << index );
  5740. }
  5741. else
  5742. {
  5743. m_DynamicState.m_UserClipPlaneEnabled &= ~( 1 << index );
  5744. }
  5745. SetRenderState( D3DRS_CLIPPLANEENABLE, m_DynamicState.m_UserClipPlaneEnabled );
  5746. }
  5747. }
  5748. // Alternate oblique projectio matrix code adapted from http://www.terathon.com/code/oblique.html
  5749. // Fixes for D3D Z range adapted from this thread: http://www.gamedev.net/community/forums/topic.asp?topic_id=398719
  5750. static inline float sgn(float a)
  5751. {
  5752. if (a > 0.0F) return (1.0F);
  5753. if (a < 0.0F) return (-1.0F);
  5754. return (0.0F);
  5755. }
  5756. // Clip plane must be in view space
  5757. void ApplyClipPlaneToProjectionMatrix( D3DXMATRIX &projMatrix, const Vector4D& clipPlane )
  5758. {
  5759. Vector4D q;
  5760. // Invalid projection matrix. (Sometimes we get in here with an identity transform as the projection matrix)
  5761. if ( projMatrix._43 == 0.0f )
  5762. {
  5763. return;
  5764. }
  5765. // Calculate the clip-space corner point opposite the clipping plane
  5766. // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
  5767. // transform it into camera space by multiplying it
  5768. // by the inverse of the projection matrix
  5769. q.x = ( sgn( clipPlane.x ) + projMatrix._31 ) / projMatrix._11;
  5770. q.y = ( sgn( clipPlane.y ) + projMatrix._32 ) / projMatrix._22;
  5771. q.z = -1.0f;
  5772. q.w = ( 1.0f + projMatrix._33 ) / projMatrix._43;
  5773. // Calculate the scaled plane vector
  5774. Vector4D c = clipPlane * ( 1.0f / DotProduct4D( clipPlane, q ) );
  5775. // Replace the third row of the projection matrix
  5776. projMatrix._13 = c.x;
  5777. projMatrix._23 = c.y;
  5778. projMatrix._33 = c.z;
  5779. projMatrix._43 = c.w;
  5780. }
  5781. ConVar mat_alternatefastclipalgorithm( "mat_alternatefastclipalgorithm", "1" );
  5782. //-----------------------------------------------------------------------------
  5783. // Recomputes the fast-clip plane matrices based on the current fast-clip plane
  5784. //-----------------------------------------------------------------------------
  5785. void CShaderAPIDx8::CommitFastClipPlane( )
  5786. {
  5787. // Don't bother recomputing if unchanged or disabled
  5788. if ( !m_DynamicState.m_bFastClipPlaneChanged || !m_DynamicState.m_FastClipEnabled )
  5789. return;
  5790. m_DynamicState.m_bFastClipPlaneChanged = false;
  5791. D3DXMatrixIdentity( &m_CachedFastClipProjectionMatrix );
  5792. // Compute worldToProjection - need inv. transpose for transforming plane.
  5793. D3DXMATRIX viewToProjInvTrans, viewToProjInv, viewToProj = GetTransform(MATERIAL_PROJECTION);
  5794. viewToProj._43 *= 0.5f; // pull in zNear because the shear in effect
  5795. // moves it out: clipping artifacts when looking down at water
  5796. // could occur if this multiply is not done
  5797. D3DXMATRIX worldToViewInvTrans, worldToViewInv, worldToView = GetUserClipTransform();
  5798. D3DXMatrixInverse( &worldToViewInv, NULL, &worldToView );
  5799. // PS3's Cg likes things in row-major rather than column-major, so let's just save ourselves the work of fixing every shader and call it even?
  5800. #ifdef _PS3
  5801. worldToViewInvTrans = worldToViewInv;
  5802. #else // _PS3
  5803. D3DXMatrixTranspose( &worldToViewInvTrans, &worldToViewInv );
  5804. #endif // !_PS3
  5805. D3DXMatrixInverse( &viewToProjInv, NULL, &viewToProj );
  5806. #ifdef _PS3
  5807. viewToProjInvTrans = viewToProjInv;
  5808. #else // _PS3
  5809. D3DXMatrixTranspose( &viewToProjInvTrans, &viewToProjInv );
  5810. #endif // !_PS3
  5811. if ( !mat_alternatefastclipalgorithm.GetBool() )
  5812. {
  5813. // OLD code path
  5814. D3DXPLANE plane;
  5815. D3DXPlaneNormalize( &plane, &m_DynamicState.m_FastClipPlane );
  5816. D3DXVECTOR4 clipPlane( plane.a, plane.b, plane.c, plane.d );
  5817. // transform clip plane into view space
  5818. D3DXVec4Transform( &clipPlane, &clipPlane, &worldToViewInvTrans );
  5819. // transform clip plane into projection space
  5820. D3DXVec4Transform( &clipPlane, &clipPlane, &viewToProjInvTrans );
  5821. #define ALLOW_FOR_FASTCLIPDUMPS 0
  5822. #if (ALLOW_FOR_FASTCLIPDUMPS == 1)
  5823. static ConVar shader_dumpfastclipprojectioncoords( "shader_dumpfastclipprojectioncoords", "0", 0, "dump fast clip projected matrix" );
  5824. if( shader_dumpfastclipprojectioncoords.GetBool() )
  5825. DevMsg( "Fast clip plane projected coordinates: %f %f %f %f", clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w );
  5826. #endif
  5827. if( (clipPlane.z * clipPlane.w) <= -0.4f ) // a plane with (z*w) > -0.4 at this point is behind the camera and will cause graphical glitches. Toss it. (0.4 found through experimentation)
  5828. {
  5829. #if (ALLOW_FOR_FASTCLIPDUMPS == 1)
  5830. if( shader_dumpfastclipprojectioncoords.GetBool() )
  5831. DevMsg( " %f %f %f %f\n", clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w );
  5832. #endif
  5833. D3DXVec4Normalize( &clipPlane, &clipPlane );
  5834. //if ((fabs(clipPlane.z) > 0.01) && (fabs(clipPlane.w) > 0.01f))
  5835. {
  5836. // put projection space clip plane in Z column
  5837. m_CachedFastClipProjectionMatrix._13 = clipPlane.x;
  5838. m_CachedFastClipProjectionMatrix._23 = clipPlane.y;
  5839. m_CachedFastClipProjectionMatrix._33 = clipPlane.z;
  5840. m_CachedFastClipProjectionMatrix._43 = clipPlane.w;
  5841. }
  5842. }
  5843. #if (ALLOW_FOR_FASTCLIPDUMPS == 1)
  5844. else
  5845. {
  5846. if( shader_dumpfastclipprojectioncoords.GetBool() )
  5847. DevMsg( "\n" ); //finish off the line above
  5848. }
  5849. #endif
  5850. m_CachedFastClipProjectionMatrix = viewToProj * m_CachedFastClipProjectionMatrix;
  5851. }
  5852. else
  5853. {
  5854. // NEW code path
  5855. D3DXPLANE plane;
  5856. D3DXPlaneNormalize( &plane, &m_DynamicState.m_FastClipPlane );
  5857. D3DXVECTOR4 clipPlane( plane.a, plane.b, plane.c, plane.d );
  5858. // transform clip plane into view space
  5859. D3DXVec4Transform( &clipPlane, &clipPlane, &worldToViewInvTrans );
  5860. m_CachedFastClipProjectionMatrix = GetTransform( MATERIAL_PROJECTION );
  5861. // Fuck with proj matrix
  5862. ApplyClipPlaneToProjectionMatrix( m_CachedFastClipProjectionMatrix, Vector4D( clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w ) );
  5863. }
  5864. // Update the cached polyoffset matrix (with clip) too:
  5865. ComputePolyOffsetMatrix( m_CachedFastClipProjectionMatrix, m_CachedFastClipPolyOffsetProjectionMatrix );
  5866. // PORTAL 2 hack: Disable slope scale z bias for decals if we have a poly offset matrix set. This avoids decals and overlays rendering
  5867. // on top of other stuff through portal views on the PS3.
  5868. if ( m_TransitionTable.CurrentShadowState() )
  5869. {
  5870. ApplyZBias( m_TransitionTable.CurrentShadowState()->m_DepthTestState );
  5871. }
  5872. }
  5873. //-----------------------------------------------------------------------------
  5874. // Sets the fast-clip plane; but doesn't update the matrices
  5875. //-----------------------------------------------------------------------------
  5876. void CShaderAPIDx8::SetFastClipPlane( const float *pPlane )
  5877. {
  5878. LOCK_SHADERAPI();
  5879. D3DXPLANE plane;
  5880. plane.a = pPlane[0];
  5881. plane.b = pPlane[1];
  5882. plane.c = pPlane[2];
  5883. plane.d = -pPlane[3];
  5884. if ( plane != m_DynamicState.m_FastClipPlane )
  5885. {
  5886. UpdateVertexShaderFogParams();
  5887. m_DynamicState.m_FastClipPlane = plane;
  5888. // Mark a dirty bit so when it comes time to commit view + projection transforms,
  5889. // we also update the fast clip matrices
  5890. m_DynamicState.m_bFastClipPlaneChanged = true;
  5891. m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |= STATE_CHANGED;
  5892. }
  5893. }
  5894. //-----------------------------------------------------------------------------
  5895. // Enables/disables fast-clip mode
  5896. //-----------------------------------------------------------------------------
  5897. void CShaderAPIDx8::EnableFastClip( bool bEnable )
  5898. {
  5899. LOCK_SHADERAPI();
  5900. if( m_DynamicState.m_FastClipEnabled != bEnable )
  5901. {
  5902. UpdateVertexShaderFogParams();
  5903. m_DynamicState.m_FastClipEnabled = bEnable;
  5904. m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |= STATE_CHANGED;
  5905. }
  5906. }
  5907. /*
  5908. // -----------------------------------------------------------------------------
  5909. // SetInvariantClipVolume - This routine takes six planes as input and sets the
  5910. // appropriate Direct3D user clip plane state
  5911. // What we mean by "invariant clipping" here is that certain devices implement
  5912. // user clip planes at the raster level, which means that multi-pass rendering
  5913. // where one pass is unclipped (such as base geometry) and another pass *IS*
  5914. // clipped (such as flashlight geometry), there is no z-fighting since the
  5915. // clipping is implemented at the raster level in an "invariant" way
  5916. // -----------------------------------------------------------------------------
  5917. void CShaderAPIDx8::SetInvariantClipVolume( Frustum_t *pFrustumPlanes )
  5918. {
  5919. // Only do this on modern nVidia hardware, which does invariant clipping
  5920. if ( m_VendorID == VENDORID_NVIDIA )
  5921. {
  5922. if ( pFrustumPlanes )
  5923. {
  5924. // if ()
  5925. // {
  5926. //
  5927. // }
  5928. for (int i=0; i<6; i++)
  5929. {
  5930. const cplane_t *pPlane = pFrustumPlanes->GetPlane(i);
  5931. SetClipPlane( i, (float *) &pPlane->normal );
  5932. EnableClipPlane( i, true );
  5933. // FRUSTUM_RIGHT = 0,
  5934. // FRUSTUM_LEFT = 1,
  5935. // FRUSTUM_TOP = 2,
  5936. // FRUSTUM_BOTTOM = 3,
  5937. // FRUSTUM_NEARZ = 4,
  5938. // FRUSTUM_FARZ = 5,
  5939. }
  5940. }
  5941. else // NULL disables the invariant clip volume...
  5942. {
  5943. for (int i=0; i<6; i++)
  5944. {
  5945. EnableClipPlane( i, false );
  5946. }
  5947. }
  5948. }
  5949. }
  5950. */
  5951. //-----------------------------------------------------------------------------
  5952. // Vertex blending
  5953. //-----------------------------------------------------------------------------
  5954. void CShaderAPIDx8::SetNumBoneWeights( int numBones )
  5955. {
  5956. LOCK_SHADERAPI();
  5957. if (m_DynamicState.m_NumBones != numBones)
  5958. {
  5959. m_DynamicState.m_NumBones = numBones;
  5960. }
  5961. }
  5962. void CShaderAPIDx8::EnableHWMorphing( bool bEnable )
  5963. {
  5964. LOCK_SHADERAPI();
  5965. if ( bEnable )
  5966. {
  5967. Assert( 0 );
  5968. Warning( "CShaderAPIDx8::EnableHWMorphing: HW morphing is getting enabled! This is not a supported code path - bad things are going to happen!\n" );
  5969. }
  5970. if ( m_DynamicState.m_bHWMorphingEnabled != bEnable )
  5971. {
  5972. m_DynamicState.m_bHWMorphingEnabled = bEnable;
  5973. }
  5974. }
  5975. void CShaderAPIDx8::EnabledSRGBWrite( bool bEnabled )
  5976. {
  5977. m_DynamicState.m_bSRGBWritesEnabled = bEnabled;
  5978. if ( g_pHardwareConfig->GetDXSupportLevel() >= 92 )
  5979. {
  5980. UpdatePixelFogColorConstant();
  5981. //if ( bEnabled && g_pHardwareConfig->NeedsShaderSRGBConversion() )
  5982. // BindTexture( SHADER_SAMPLER15, m_hLinearToGammaTableTexture );
  5983. //else
  5984. // BindTexture( SHADER_SAMPLER15, m_hLinearToGammaTableIdentityTexture );
  5985. }
  5986. }
  5987. void CShaderAPIDx8::SetSRGBWrite( bool bState )
  5988. {
  5989. SetSupportedRenderState( D3DRS_SRGBWRITEENABLE, ( bState ) ? 1 : 0 );
  5990. m_DynamicState.m_bSRGBWritesEnabled = bState;
  5991. }
  5992. //-----------------------------------------------------------------------------
  5993. // Fog methods...
  5994. //-----------------------------------------------------------------------------
  5995. void CShaderAPIDx8::UpdatePixelFogColorConstant( bool bMultiplyByToneMapScale )
  5996. {
  5997. Assert( HardwareConfig()->GetDXSupportLevel() >= 92 );
  5998. float flDestAlphaDepthRange = GetFloatRenderingParameter( FLOAT_RENDERPARM_DEST_ALPHA_DEPTH_SCALE );
  5999. float flInvDestAlphaDepthRange = flDestAlphaDepthRange > 0.0f ? 1.0f / flDestAlphaDepthRange : 0.0f;
  6000. Vector4D vecFogColor( 0.0f, 0.0f, 0.0f, flInvDestAlphaDepthRange );
  6001. switch( GetSceneFogMode() )
  6002. {
  6003. case MATERIAL_FOG_NONE:
  6004. // Don't worry about fog color since we aren't going to use it
  6005. // Even so, we do need to set LINEAR_FOG_COLOR since w component controls soft particles
  6006. break;
  6007. case MATERIAL_FOG_LINEAR:
  6008. {
  6009. //setup the fog for mixing linear fog in the pixel shader so that it emulates ff range fog
  6010. if( m_DynamicState.m_bSRGBWritesEnabled )
  6011. {
  6012. vecFogColor.AsVector3D() = m_DynamicState.m_vecPixelFogColorLinear.AsVector3D();
  6013. }
  6014. else
  6015. {
  6016. vecFogColor.AsVector3D() = m_DynamicState.m_vecPixelFogColor.AsVector3D();
  6017. }
  6018. }
  6019. break;
  6020. case MATERIAL_FOG_LINEAR_BELOW_FOG_Z:
  6021. {
  6022. //water fog has been around a while and has never tonemap scaled, and has always been in linear space
  6023. if( g_pHardwareConfig->NeedsShaderSRGBConversion() )
  6024. {
  6025. // srgb in ps2b uses the 2.2 curve
  6026. for( int i = 0; i < 3; ++i )
  6027. {
  6028. vecFogColor[i] = pow( m_DynamicState.m_vecPixelFogColor[i], 2.2f );
  6029. }
  6030. }
  6031. else
  6032. {
  6033. vecFogColor.AsVector3D() = m_DynamicState.m_vecPixelFogColorLinear.AsVector3D(); //this is how water fog color has always been setup in the past
  6034. }
  6035. }
  6036. break;
  6037. NO_DEFAULT;
  6038. };
  6039. if( bMultiplyByToneMapScale && ( (!m_DynamicState.m_bFogGammaCorrectionDisabled) && (g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) ) )
  6040. {
  6041. vecFogColor.AsVector3D() *= m_ToneMappingScale.x;
  6042. }
  6043. SetPixelShaderConstantInternal( LINEAR_FOG_COLOR, vecFogColor.Base() );
  6044. }
  6045. FogMethod_t CShaderAPIDx8::ComputeFogMethod( ShaderFogMode_t shaderFogMode, MaterialFogMode_t sceneFogMode, bool bVertexFog )
  6046. {
  6047. if ( sceneFogMode == MATERIAL_FOG_LINEAR_BELOW_FOG_Z )
  6048. {
  6049. return FOGMETHOD_PIXELSHADERFOG;
  6050. }
  6051. if ( HardwareConfig()->GetDXSupportLevel() <= 90 )
  6052. {
  6053. // ps20 always uses fixed-function fog if there is no water.
  6054. return FOGMETHOD_FIXEDFUNCTIONVERTEXFOG;
  6055. }
  6056. // use the vmt's $vertexfog param to decide what to do.
  6057. if ( bVertexFog )
  6058. {
  6059. return FOGMETHOD_VERTEXFOGBLENDEDINPIXELSHADER;
  6060. }
  6061. else
  6062. {
  6063. return FOGMETHOD_PIXELSHADERFOG;
  6064. }
  6065. }
  6066. Vector CShaderAPIDx8::CalculateFogColorConstant( D3DCOLOR *pPackedColorOut, FogMethod_t fogMethod, ShaderFogMode_t fogMode,
  6067. bool bDisableFogGammaCorrection, bool bSRGBWritesEnabled )
  6068. {
  6069. if ( fogMode == SHADER_FOGMODE_DISABLED )
  6070. {
  6071. return Vector( 0, 0, 0 );
  6072. }
  6073. bool bShouldGammaCorrect = true; // By default, we'll gamma correct.
  6074. uint8 r = 0, g = 0, b = 0; // Black fog
  6075. switch( fogMode )
  6076. {
  6077. case SHADER_FOGMODE_BLACK: // Additive decals
  6078. bShouldGammaCorrect = false;
  6079. break;
  6080. case SHADER_FOGMODE_OO_OVERBRIGHT:
  6081. case SHADER_FOGMODE_GREY: // Mod2x decals
  6082. r = g = b = 128;
  6083. break;
  6084. case SHADER_FOGMODE_WHITE: // Multiplicative decals
  6085. r = g = b = 255;
  6086. bShouldGammaCorrect = false;
  6087. break;
  6088. case SHADER_FOGMODE_FOGCOLOR:
  6089. GetSceneFogColor( &r, &g, &b ); // Scene fog color
  6090. break;
  6091. NO_DEFAULT
  6092. }
  6093. bShouldGammaCorrect &= !bDisableFogGammaCorrection;
  6094. const float fColorScale = 1.0f / 255.0f;
  6095. Vector vecRet;
  6096. vecRet.x = (float)(r) * fColorScale;
  6097. vecRet.y = (float)(g) * fColorScale;
  6098. vecRet.z = (float)(b) * fColorScale;
  6099. if ( pPackedColorOut )
  6100. {
  6101. D3DCOLOR color;
  6102. if ( bShouldGammaCorrect )
  6103. {
  6104. color = ComputeGammaCorrectedFogColor( r, g, b, bSRGBWritesEnabled );
  6105. }
  6106. else
  6107. {
  6108. color = D3DCOLOR_ARGB( 255, r, g, b );
  6109. }
  6110. ( *pPackedColorOut ) = color;
  6111. }
  6112. return vecRet;
  6113. }
  6114. struct FogConstants_t
  6115. {
  6116. Vector m_vecFogColorConstant[FOGMETHOD_NUMVALUES][SHADER_FOGMODE_NUMFOGMODES][2][2]; // [fogMode][bDisableFogGammaCorrection][bSRGBWritesEnabled]
  6117. Vector m_vecFogColorConstantLinear[FOGMETHOD_NUMVALUES][SHADER_FOGMODE_NUMFOGMODES][2][2]; // [fogMode][bDisableFogGammaCorrection][bSRGBWritesEnabled]
  6118. D3DCOLOR m_nPackedFogColorConstants[FOGMETHOD_NUMVALUES][SHADER_FOGMODE_NUMFOGMODES][2][2];
  6119. };
  6120. static FogConstants_t s_CurFogConstants;
  6121. static bool s_bFirstTimeGeneratingConstants = true;
  6122. void CShaderAPIDx8::RegenerateFogConstants( void )
  6123. {
  6124. for( int nMethod = 0; nMethod < FOGMETHOD_NUMVALUES; nMethod++ )
  6125. {
  6126. for( int nMode = 0; nMode < SHADER_FOGMODE_NUMFOGMODES; nMode++ )
  6127. {
  6128. if ( ( ! s_bFirstTimeGeneratingConstants ) && ( nMode != SHADER_FOGMODE_FOGCOLOR ) )
  6129. continue; // state changes don't effect any mode execpt FOGCOLOR
  6130. for( int nDisabledFogGammaCorrection = 0; nDisabledFogGammaCorrection < 2; nDisabledFogGammaCorrection++ )
  6131. {
  6132. for( int nSRGBWritesEnabled = 0; nSRGBWritesEnabled < 2 ; nSRGBWritesEnabled++ )
  6133. {
  6134. s_CurFogConstants.m_vecFogColorConstant[nMethod][nMode][nDisabledFogGammaCorrection][nSRGBWritesEnabled] = CalculateFogColorConstant(
  6135. &( s_CurFogConstants.m_nPackedFogColorConstants[nMethod][nMode][nDisabledFogGammaCorrection][nSRGBWritesEnabled] ),
  6136. ( FogMethod_t ) nMethod, ( ShaderFogMode_t ) nMode, ( nDisabledFogGammaCorrection != 0 ), ( nSRGBWritesEnabled != 0 ) );
  6137. // generate linear versions
  6138. for( int i = 0; i < 3; i++ )
  6139. {
  6140. float *pComponent = &( s_CurFogConstants.m_vecFogColorConstantLinear[nMethod][nMode][nDisabledFogGammaCorrection][nSRGBWritesEnabled][i] );
  6141. float *pSrcComponent = &( s_CurFogConstants.m_vecFogColorConstant[nMethod][nMode][nDisabledFogGammaCorrection][nSRGBWritesEnabled][i] );
  6142. *( pComponent ) = GammaToLinear_HardwareSpecific( *pSrcComponent );
  6143. }
  6144. }
  6145. }
  6146. }
  6147. }
  6148. s_bFirstTimeGeneratingConstants = false; // next time around, don't regenerate the whole table
  6149. }
  6150. void CShaderAPIDx8::ApplyFogMode( ShaderFogMode_t fogMode, bool bVertexFog, bool bSRGBWritesEnabled, bool bDisableFogGammaCorrection )
  6151. {
  6152. FogMethod_t fogMethod = ComputeFogMethod( fogMode, m_SceneFogMode, bVertexFog );
  6153. if ( fogMethod != FOGMETHOD_PIXELSHADERFOG )
  6154. {
  6155. UpdateVertexShaderFogParams( fogMode, bVertexFog );
  6156. }
  6157. if ( fogMode == SHADER_FOGMODE_DISABLED )
  6158. {
  6159. // Turn off fixed-function fog if it's currently enabled.
  6160. EnableFixedFunctionFog( false );
  6161. if ( m_DelayedShaderConstants.iPixelShaderFogParams != -1 )
  6162. {
  6163. SetPixelShaderFogParams( m_DelayedShaderConstants.iPixelShaderFogParams, fogMode );
  6164. }
  6165. return;
  6166. }
  6167. D3DCOLOR fixedFunctionFogPackedColor = s_CurFogConstants.m_nPackedFogColorConstants[fogMethod][fogMode][bDisableFogGammaCorrection][bSRGBWritesEnabled ];
  6168. Vector vecFogColor = s_CurFogConstants.m_vecFogColorConstant[fogMethod][fogMode][bDisableFogGammaCorrection][bSRGBWritesEnabled];
  6169. Vector vecFogColorLinear = s_CurFogConstants.m_vecFogColorConstantLinear[fogMethod][fogMode][bDisableFogGammaCorrection][bSRGBWritesEnabled];
  6170. // Enable fixed-function fog if we are using it.
  6171. EnableFixedFunctionFog( ( fogMethod == FOGMETHOD_FIXEDFUNCTIONVERTEXFOG ) && ( m_SceneFogMode != MATERIAL_FOG_NONE ) );
  6172. if( m_DelayedShaderConstants.iPixelShaderFogParams != -1 )
  6173. {
  6174. // We set these for all methods since the pixel shader is always effectively doing fog, even when fog is disabled.
  6175. SetPixelShaderFogParams( m_DelayedShaderConstants.iPixelShaderFogParams, fogMode );
  6176. }
  6177. //?m_DynamicState.m_bFogGammaCorrectionDisabled = !bShouldGammaCorrect;
  6178. m_DynamicState.m_vecPixelFogColor.AsVector3D() = vecFogColor;
  6179. m_DynamicState.m_vecPixelFogColorLinear.AsVector3D() = vecFogColorLinear;
  6180. if ( fogMethod != FOGMETHOD_FIXEDFUNCTIONVERTEXFOG )
  6181. {
  6182. // All fog methods other than FOGMETHOD_FIXEDFUNCTIONVERTEXFOG use fog color int he pixel shader.
  6183. UpdatePixelFogColorConstant( fogMode != SHADER_FOGMODE_GREY );
  6184. }
  6185. if ( ( fogMethod == FOGMETHOD_FIXEDFUNCTIONVERTEXFOG ) && ( fixedFunctionFogPackedColor != m_DynamicState.m_FogColor ) )
  6186. {
  6187. // Set the hardware fog color for the one fog method that uses it, FOGMETHOD_FIXEDFUNCTIONVERTEXFOG.
  6188. m_DynamicState.m_FogColor = fixedFunctionFogPackedColor;
  6189. SetSupportedRenderState( D3DRS_FOGCOLOR, m_DynamicState.m_FogColor );
  6190. }
  6191. }
  6192. void CShaderAPIDx8::SceneFogMode( MaterialFogMode_t fogMode )
  6193. {
  6194. LOCK_SHADERAPI();
  6195. if( m_SceneFogMode != fogMode )
  6196. {
  6197. m_SceneFogMode = fogMode;
  6198. if ( m_TransitionTable.CurrentShadowState() )
  6199. {
  6200. // Get the shadow state in sync since it depends on SceneFogMode.
  6201. ApplyFogMode( m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.FogMode(), m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_bVertexFogEnable, m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_SRGBWriteEnable, m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_bDisableFogGammaCorrection );
  6202. }
  6203. }
  6204. }
  6205. MaterialFogMode_t CShaderAPIDx8::GetSceneFogMode()
  6206. {
  6207. return m_SceneFogMode;
  6208. }
  6209. int CShaderAPIDx8::GetPixelFogCombo( void )
  6210. {
  6211. Assert( 0 ); // deprecated
  6212. return 0;
  6213. }
  6214. //-----------------------------------------------------------------------------
  6215. // Fog methods...
  6216. //-----------------------------------------------------------------------------
  6217. void CShaderAPIDx8::EnableFixedFunctionFog( bool bFogEnable )
  6218. {
  6219. if ( IsGameConsole() )
  6220. {
  6221. // FF fog not applicable on 360 / PS3
  6222. return;
  6223. }
  6224. // Set fog enable if it's different than before.
  6225. if ( bFogEnable != m_DynamicState.m_FogEnable )
  6226. {
  6227. SetSupportedRenderState( D3DRS_FOGENABLE, bFogEnable );
  6228. m_DynamicState.m_FogEnable = bFogEnable;
  6229. }
  6230. }
  6231. void CShaderAPIDx8::FogStart( float fStart )
  6232. {
  6233. LOCK_SHADERAPI();
  6234. if (fStart != m_DynamicState.m_FogStart)
  6235. {
  6236. SetSupportedRenderState(D3DRS_FOGSTART, *((DWORD*)(&fStart)));
  6237. m_VertexShaderFogParams[0] = fStart;
  6238. UpdateVertexShaderFogParams();
  6239. m_DynamicState.m_FogStart = fStart;
  6240. }
  6241. }
  6242. void CShaderAPIDx8::FogEnd( float fEnd )
  6243. {
  6244. LOCK_SHADERAPI();
  6245. if (fEnd != m_DynamicState.m_FogEnd)
  6246. {
  6247. SetSupportedRenderState(D3DRS_FOGEND, *((DWORD*)(&fEnd)));
  6248. m_VertexShaderFogParams[1] = fEnd;
  6249. UpdateVertexShaderFogParams();
  6250. m_DynamicState.m_FogEnd = fEnd;
  6251. }
  6252. }
  6253. void CShaderAPIDx8::SetFogZ( float fogZ )
  6254. {
  6255. LOCK_SHADERAPI();
  6256. if (fogZ != m_DynamicState.m_FogZ)
  6257. {
  6258. m_DynamicState.m_FogZ = fogZ;
  6259. UpdateVertexShaderFogParams();
  6260. }
  6261. }
  6262. void CShaderAPIDx8::FogMaxDensity( float flMaxDensity )
  6263. {
  6264. LOCK_SHADERAPI();
  6265. if (flMaxDensity != m_DynamicState.m_FogMaxDensity)
  6266. {
  6267. // SetRenderState(D3DRS_FOGDENSITY, *((DWORD*)(&flMaxDensity))); // ??? do I need to to this ???
  6268. m_flFogMaxDensity = flMaxDensity;
  6269. UpdateVertexShaderFogParams();
  6270. m_DynamicState.m_FogMaxDensity = flMaxDensity;
  6271. }
  6272. }
  6273. void CShaderAPIDx8::GetFogDistances( float *fStart, float *fEnd, float *fFogZ )
  6274. {
  6275. LOCK_SHADERAPI();
  6276. if( fStart )
  6277. *fStart = m_DynamicState.m_FogStart;
  6278. if( fEnd )
  6279. *fEnd = m_DynamicState.m_FogEnd;
  6280. if( fFogZ )
  6281. *fFogZ = m_DynamicState.m_FogZ;
  6282. }
  6283. void CShaderAPIDx8::SceneFogColor3ub( unsigned char r, unsigned char g, unsigned char b )
  6284. {
  6285. LOCK_SHADERAPI();
  6286. if( m_SceneFogColor[0] != r || m_SceneFogColor[1] != g || m_SceneFogColor[2] != b )
  6287. {
  6288. m_SceneFogColor[0] = r;
  6289. m_SceneFogColor[1] = g;
  6290. m_SceneFogColor[2] = b;
  6291. RegenerateFogConstants();
  6292. if ( m_TransitionTable.CurrentShadowState() )
  6293. {
  6294. ApplyFogMode( m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.FogMode(), m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_bVertexFogEnable, m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_SRGBWriteEnable, m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_bDisableFogGammaCorrection );
  6295. }
  6296. }
  6297. }
  6298. void CShaderAPIDx8::GetSceneFogColor( unsigned char *rgb )
  6299. {
  6300. LOCK_SHADERAPI();
  6301. rgb[0] = m_SceneFogColor[0];
  6302. rgb[1] = m_SceneFogColor[1];
  6303. rgb[2] = m_SceneFogColor[2];
  6304. }
  6305. void CShaderAPIDx8::GetSceneFogColor( unsigned char *r, unsigned char *g, unsigned char *b )
  6306. {
  6307. *r = m_SceneFogColor[0];
  6308. *g = m_SceneFogColor[1];
  6309. *b = m_SceneFogColor[2];
  6310. }
  6311. //-----------------------------------------------------------------------------
  6312. // Gamma correction of fog color, or not...
  6313. //-----------------------------------------------------------------------------
  6314. D3DCOLOR CShaderAPIDx8::ComputeGammaCorrectedFogColor( unsigned char r, unsigned char g, unsigned char b, bool bSRGBWritesEnabled )
  6315. {
  6316. #ifdef _DEBUG
  6317. if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT && !bSRGBWritesEnabled )
  6318. {
  6319. // Assert( 0 );
  6320. }
  6321. #endif
  6322. bool bLinearSpace = g_pHardwareConfig->Caps().m_bFogColorAlwaysLinearSpace ||
  6323. ( bSRGBWritesEnabled && ( g_pHardwareConfig->Caps().m_bFogColorSpecifiedInLinearSpace || g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) );
  6324. bool bScaleFogByToneMappingScale = g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER;
  6325. float fr = ( r / 255.0f );
  6326. float fg = ( g / 255.0f );
  6327. float fb = ( b / 255.0f );
  6328. if ( bLinearSpace )
  6329. {
  6330. fr = GammaToLinear( fr );
  6331. fg = GammaToLinear( fg );
  6332. fb = GammaToLinear( fb );
  6333. if ( bScaleFogByToneMappingScale )
  6334. {
  6335. fr *= m_ToneMappingScale.x; //
  6336. fg *= m_ToneMappingScale.x; // Linear
  6337. fb *= m_ToneMappingScale.x; //
  6338. }
  6339. }
  6340. else if ( bScaleFogByToneMappingScale )
  6341. {
  6342. fr *= m_ToneMappingScale.w; //
  6343. fg *= m_ToneMappingScale.w; // Gamma
  6344. fb *= m_ToneMappingScale.w; //
  6345. }
  6346. fr = MIN( fr, 1.0f );
  6347. fg = MIN( fg, 1.0f );
  6348. fb = MIN( fb, 1.0f );
  6349. r = (int)( fr * 255 );
  6350. g = (int)( fg * 255 );
  6351. b = (int)( fb * 255 );
  6352. return D3DCOLOR_ARGB( 255, r, g, b );
  6353. }
  6354. //-----------------------------------------------------------------------------
  6355. // Some methods chaining vertex + pixel shaders through to the shader manager
  6356. //-----------------------------------------------------------------------------
  6357. void CShaderAPIDx8::SetVertexShaderIndex( int vshIndex )
  6358. {
  6359. ShaderManager()->SetVertexShaderIndex( vshIndex );
  6360. }
  6361. void CShaderAPIDx8::SetPixelShaderIndex( int pshIndex )
  6362. {
  6363. ShaderManager()->SetPixelShaderIndex( pshIndex );
  6364. }
  6365. void CShaderAPIDx8::SyncToken( const char *pToken )
  6366. {
  6367. LOCK_SHADERAPI();
  6368. RECORD_COMMAND( DX8_SYNC_TOKEN, 1 );
  6369. RECORD_STRING( pToken );
  6370. }
  6371. //-----------------------------------------------------------------------------
  6372. // Deals with vertex buffers
  6373. //-----------------------------------------------------------------------------
  6374. void CShaderAPIDx8::DestroyVertexBuffers( bool bExitingLevel )
  6375. {
  6376. LOCK_SHADERAPI();
  6377. MeshMgr()->DestroyVertexBuffers( );
  6378. // After a map is shut down, we switch to using smaller dynamic VBs
  6379. // (VGUI shouldn't need much), so that we have more memory free during map loading
  6380. m_nDynamicVBSize = ( bExitingLevel && !mat_do_not_shrink_dynamic_vb.GetBool() ) ? DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL : DYNAMIC_VERTEX_BUFFER_MEMORY;
  6381. }
  6382. int CShaderAPIDx8::GetCurrentDynamicVBSize( void )
  6383. {
  6384. return m_nDynamicVBSize;
  6385. }
  6386. #ifdef _PS3
  6387. FORCEINLINE void CShaderAPIDx8::SetVertexShaderConstantInternal( int var, float const* pVec, int numVecs, bool bForce )
  6388. {
  6389. Dx9Device()->SetVertexShaderConstantF( var, pVec, numVecs );
  6390. }
  6391. #else
  6392. FORCEINLINE void CShaderAPIDx8::SetVertexShaderConstantInternal( int var, float const* pVec, int numVecs, bool bForce )
  6393. {
  6394. Assert( numVecs > 0 );
  6395. Assert( pVec );
  6396. if ( IsPC() || IsPS3() )
  6397. {
  6398. Assert( var + numVecs <= g_pHardwareConfig->NumVertexShaderConstants() );
  6399. if ( !bForce && memcmp( pVec, &m_DynamicState.m_pVectorVertexShaderConstant[var], numVecs * 4 * sizeof( float ) ) == 0 )
  6400. return;
  6401. Dx9Device()->SetVertexShaderConstantF( var, pVec, numVecs );
  6402. memcpy( &m_DynamicState.m_pVectorVertexShaderConstant[var], pVec, numVecs * 4 * sizeof(float) );
  6403. }
  6404. else
  6405. {
  6406. Assert( var + numVecs <= g_pHardwareConfig->NumVertexShaderConstants() );
  6407. }
  6408. if ( IsX360() )
  6409. {
  6410. if ( !IsGPUOwnSupported() || !m_bGPUOwned )
  6411. {
  6412. Dx9Device()->SetVertexShaderConstantF( var, pVec, numVecs );
  6413. memcpy( &m_DynamicState.m_pVectorVertexShaderConstant[var], pVec, numVecs * 4 * sizeof(float) );
  6414. }
  6415. else if ( var + numVecs > m_MaxVectorVertexShaderConstant )
  6416. {
  6417. m_MaxVectorVertexShaderConstant = var + numVecs;
  6418. }
  6419. }
  6420. memcpy( &m_DesiredState.m_pVectorVertexShaderConstant[var], pVec, numVecs * 4 * sizeof(float) );
  6421. }
  6422. #endif
  6423. //-----------------------------------------------------------------------------
  6424. // Sets the constant register for vertex and pixel shaders
  6425. //-----------------------------------------------------------------------------
  6426. void CShaderAPIDx8::SetVertexShaderConstant( int var, float const* pVec, int numVecs, bool bForce )
  6427. {
  6428. SetVertexShaderConstantInternal( var, pVec, numVecs, bForce );
  6429. }
  6430. void CShaderAPIDx8::GenerateNonInstanceRenderState( MeshInstanceData_t *pInstance, CompiledLightingState_t** ppCompiledState, InstanceInfo_t **ppCompiledInfo )
  6431. {
  6432. memset( pInstance, 0, sizeof(MeshInstanceData_t) );
  6433. pInstance->m_pLightingState = &m_DynamicState.m_LightingState;
  6434. if ( m_maxBoneLoaded && m_DynamicState.m_NumBones )
  6435. {
  6436. pInstance->m_nBoneCount = m_maxBoneLoaded + 1;
  6437. pInstance->m_pPoseToWorld = m_boneMatrix;
  6438. m_maxBoneLoaded = 0;
  6439. }
  6440. else
  6441. {
  6442. // casting from 4x3 matrices to a 4x4 D3DXMATRIX, need 4 floats of overflow
  6443. float results[12+4];
  6444. D3DXMatrixTranspose( (D3DXMATRIX *)&results[0], &GetTransform( MATERIAL_MODEL ) );
  6445. memcpy( m_boneMatrix[0].Base(), results, 12 * sizeof(float) );
  6446. pInstance->m_nBoneCount = 1;
  6447. pInstance->m_pPoseToWorld = m_boneMatrix;
  6448. }
  6449. *ppCompiledState = &m_DynamicState.m_CompiledLightingState;
  6450. *ppCompiledInfo = &m_DynamicState.m_InstanceInfo;
  6451. }
  6452. void CShaderAPIDx8::NotifyShaderConstantsChangedInRenderPass()
  6453. {
  6454. #if defined( _X360 )
  6455. // send updated shader constants to gpu
  6456. WriteShaderConstantsToGPU();
  6457. #endif
  6458. }
  6459. //-----------------------------------------------------------------------------
  6460. // Sets the boolean registers for vertex shader control flow
  6461. //-----------------------------------------------------------------------------
  6462. void CShaderAPIDx8::SetBooleanVertexShaderConstant( int var, int const* pVec, int numBools, bool bForce )
  6463. {
  6464. Assert( pVec );
  6465. Assert( var + numBools <= g_pHardwareConfig->NumBooleanVertexShaderConstants() );
  6466. if ( IsPC() && !bForce && memcmp( pVec, &m_DesiredState.m_pBooleanVertexShaderConstant[var], numBools * sizeof( BOOL ) ) == 0 )
  6467. {
  6468. return;
  6469. }
  6470. if ( IsPC() || IsPS3() )
  6471. {
  6472. Dx9Device()->SetVertexShaderConstantB( var, pVec, numBools );
  6473. memcpy( &m_DynamicState.m_pBooleanVertexShaderConstant[var], pVec, numBools * sizeof(BOOL) );
  6474. }
  6475. if ( IsX360() )
  6476. {
  6477. if ( !IsGPUOwnSupported() || !m_bGPUOwned )
  6478. {
  6479. Dx9Device()->SetVertexShaderConstantB( var, pVec, numBools );
  6480. if ( IsGPUOwnSupported() )
  6481. {
  6482. memcpy( &m_DynamicState.m_pBooleanVertexShaderConstant[var], pVec, numBools * sizeof(BOOL) );
  6483. }
  6484. }
  6485. else if ( var + numBools > m_MaxBooleanVertexShaderConstant )
  6486. {
  6487. m_MaxBooleanVertexShaderConstant = var + numBools;
  6488. Assert( m_MaxBooleanVertexShaderConstant <= 16 );
  6489. }
  6490. }
  6491. memcpy( &m_DesiredState.m_pBooleanVertexShaderConstant[var], pVec, numBools * sizeof(BOOL) );
  6492. }
  6493. //-----------------------------------------------------------------------------
  6494. // Sets the integer registers for vertex shader control flow
  6495. //-----------------------------------------------------------------------------
  6496. void CShaderAPIDx8::SetIntegerVertexShaderConstant( int var, int const* pVec, int numIntVecs, bool bForce )
  6497. {
  6498. Assert( pVec );
  6499. Assert( var + numIntVecs <= g_pHardwareConfig->NumIntegerVertexShaderConstants() );
  6500. if ( IsPC() && !bForce && memcmp( pVec, &m_DesiredState.m_pIntegerVertexShaderConstant[var], numIntVecs * sizeof( IntVector4D ) ) == 0 )
  6501. {
  6502. return;
  6503. }
  6504. if ( IsPC() || IsPS3() )
  6505. {
  6506. Dx9Device()->SetVertexShaderConstantI( var, pVec, numIntVecs );
  6507. memcpy( &m_DynamicState.m_pIntegerVertexShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
  6508. }
  6509. if ( IsX360() )
  6510. {
  6511. if ( !IsGPUOwnSupported() || !m_bGPUOwned )
  6512. {
  6513. Dx9Device()->SetVertexShaderConstantI( var, pVec, numIntVecs );
  6514. if ( IsGPUOwnSupported() )
  6515. {
  6516. memcpy( &m_DynamicState.m_pIntegerVertexShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
  6517. }
  6518. }
  6519. else if ( var + numIntVecs > m_MaxIntegerVertexShaderConstant )
  6520. {
  6521. m_MaxIntegerVertexShaderConstant = var + numIntVecs;
  6522. Assert( m_MaxIntegerVertexShaderConstant <= 16 );
  6523. }
  6524. }
  6525. memcpy( &m_DesiredState.m_pIntegerVertexShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
  6526. }
  6527. #ifndef _PS3
  6528. FORCEINLINE void CShaderAPIDx8::SetPixelShaderConstantInternal( int nStartConst, float const* pValues, int nNumConsts, bool bForce )
  6529. {
  6530. Assert( nStartConst + nNumConsts <= g_pHardwareConfig->NumPixelShaderConstants() );
  6531. if ( IsPC() || IsPS3() )
  6532. {
  6533. if ( !bForce )
  6534. {
  6535. DWORD* pSrc = (DWORD*)pValues;
  6536. DWORD* pDst = (DWORD*)&m_DesiredState.m_pVectorPixelShaderConstant[nStartConst];
  6537. while( nNumConsts && ( pSrc[0] == pDst[0] ) && ( pSrc[1] == pDst[1] ) && ( pSrc[2] == pDst[2] ) && ( pSrc[3] == pDst[3] ) )
  6538. {
  6539. pSrc += 4;
  6540. pDst += 4;
  6541. nNumConsts--;
  6542. nStartConst++;
  6543. }
  6544. if ( !nNumConsts )
  6545. return;
  6546. pValues = reinterpret_cast< float const * >( pSrc );
  6547. }
  6548. Dx9Device()->SetPixelShaderConstantF( nStartConst, pValues, nNumConsts );
  6549. memcpy( &m_DynamicState.m_pVectorPixelShaderConstant[nStartConst], pValues, nNumConsts * 4 * sizeof(float) );
  6550. }
  6551. if ( IsX360() )
  6552. {
  6553. if ( !IsGPUOwnSupported() || !m_bGPUOwned )
  6554. {
  6555. Dx9Device()->SetPixelShaderConstantF( nStartConst, pValues, nNumConsts );
  6556. if ( IsGPUOwnSupported() )
  6557. {
  6558. memcpy( &m_DynamicState.m_pVectorPixelShaderConstant[nStartConst], pValues, nNumConsts * 4 * sizeof(float) );
  6559. }
  6560. }
  6561. else if ( nStartConst + nNumConsts > m_MaxVectorPixelShaderConstant )
  6562. {
  6563. m_MaxVectorPixelShaderConstant = nStartConst + nNumConsts;
  6564. Assert( m_MaxVectorPixelShaderConstant <= 32 );
  6565. if ( m_MaxVectorPixelShaderConstant > 32 )
  6566. {
  6567. // NOTE! There really are 224 pixel shader constants on the 360, but we do an optimization that only blasts the first 32 always.
  6568. Error( "Don't use more then the first 32 pixel shader constants on the 360!" );
  6569. }
  6570. }
  6571. }
  6572. memcpy( &m_DesiredState.m_pVectorPixelShaderConstant[nStartConst], pValues, nNumConsts * 4 * sizeof(float) );
  6573. }
  6574. #endif
  6575. void CShaderAPIDx8::SetPixelShaderConstant( int var, float const* pVec, int numVecs, bool bForce )
  6576. {
  6577. SetPixelShaderConstantInternal( var, pVec, numVecs, bForce );
  6578. }
  6579. template<class T> FORCEINLINE T GetData( uint8 const *pData )
  6580. {
  6581. return * ( reinterpret_cast< T const *>( pData ) );
  6582. }
  6583. void CShaderAPIDx8::SetStandardTextureHandle( StandardTextureId_t nId, ShaderAPITextureHandle_t nHandle )
  6584. {
  6585. Assert( nId < ARRAYSIZE( m_StdTextureHandles ) );
  6586. m_StdTextureHandles[nId] = nHandle;
  6587. if ( nId == TEXTURE_LOCAL_ENV_CUBEMAP )
  6588. {
  6589. m_DynamicState.m_nLocalEnvCubemapSamplers = 0;
  6590. // NOTE: We could theoretically recompute localenvcubemapsamplers,
  6591. // but this will happen outside of rendering shaders, so it won't matter
  6592. }
  6593. if ( nId == TEXTURE_LIGHTMAP )
  6594. {
  6595. m_DynamicState.m_nLightmapSamplers = 0;
  6596. }
  6597. if ( nId == TEXTURE_PAINT )
  6598. {
  6599. m_DynamicState.m_nPaintmapSamplers = 0;
  6600. }
  6601. }
  6602. void CShaderAPIDx8::DrawInstances( int nInstanceCount, const MeshInstanceData_t *pInstances )
  6603. {
  6604. MeshMgr()->DrawInstances( nInstanceCount, pInstances );
  6605. }
  6606. #ifdef _PS3
  6607. void CShaderAPIDx8::ExecuteCommandBuffer( uint8 *pCmdBuf )
  6608. {
  6609. gpGcmDrawState->SetWorldSpaceCameraPosition((float*)&m_WorldSpaceCameraPosition);
  6610. gpGcmDrawState->ExecuteCommandBuffer(pCmdBuf);
  6611. }
  6612. void CShaderAPIDx8::ExecuteCommandBufferPPU( uint8 *pCmdBuf )
  6613. {
  6614. uint8 *pReturnStack[20];
  6615. uint8 **pSP = &pReturnStack[ARRAYSIZE(pReturnStack)];
  6616. uint8 *pLastCmd;
  6617. for(;;)
  6618. {
  6619. uint8 *pCmd=pCmdBuf;
  6620. int nCmd = GetData<int>( pCmdBuf );
  6621. switch( nCmd )
  6622. {
  6623. case CBCMD_LENGTH:
  6624. {
  6625. pCmdBuf += sizeof(int) *2 ;
  6626. break;
  6627. }
  6628. case CBCMD_PS3TEX:
  6629. {
  6630. pCmdBuf += sizeof(int) + (CBCMD_MAX_PS3TEX*sizeof(int));
  6631. break;
  6632. }
  6633. case CBCMD_END:
  6634. {
  6635. if ( pSP == &pReturnStack[ARRAYSIZE(pReturnStack)] )
  6636. return;
  6637. else
  6638. {
  6639. // pop pc
  6640. pCmdBuf = *( pSP ++ );
  6641. break;
  6642. }
  6643. }
  6644. case CBCMD_JUMP:
  6645. pCmdBuf = GetData<uint8 *>( pCmdBuf + sizeof( int ) );
  6646. break;
  6647. case CBCMD_JSR:
  6648. {
  6649. Assert( pSP > &(pReturnStack[0] ) );
  6650. // *(--pSP ) = pCmdBuf + sizeof( int ) + sizeof( uint8 *);
  6651. // pCmdBuf = GetData<uint8 *>( pCmdBuf + sizeof( int ) );
  6652. ExecuteCommandBuffer( GetData<uint8 *>( pCmdBuf + sizeof( int ) ) );
  6653. pCmdBuf = pCmdBuf + sizeof( int ) + sizeof( uint8 *);
  6654. break;
  6655. }
  6656. case CBCMD_SET_VERTEX_SHADER_FLASHLIGHT_STATE:
  6657. {
  6658. int nStartConst = GetData<int>( pCmdBuf + sizeof( int ) );
  6659. SetVertexShaderConstantInternal( nStartConst, m_FlashlightWorldToTexture.Base(), 4, false );
  6660. pCmdBuf += 2 * sizeof( int );
  6661. break;
  6662. }
  6663. case CBCMD_SET_PIXEL_SHADER_FLASHLIGHT_STATE:
  6664. {
  6665. int nLightSampler = GetData<int>( pCmdBuf + sizeof( int ) );
  6666. int nDepthSampler = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
  6667. int nShadowNoiseSampler = GetData<int>( pCmdBuf + 3 * sizeof( int ) );
  6668. int nColorConst = GetData<int>( pCmdBuf + 4 * sizeof( int ) );
  6669. int nAttenConst = GetData<int>( pCmdBuf + 5 * sizeof( int ) );
  6670. int nOriginConst = GetData<int>( pCmdBuf + 6 * sizeof( int ) );
  6671. int nDepthTweakConst = GetData<int>( pCmdBuf + 7 * sizeof( int ) );
  6672. int nScreenScaleConst = GetData<int>( pCmdBuf + 8 * sizeof( int ) );
  6673. int nWorldToTextureConstant = GetData<int>( pCmdBuf + 9 * sizeof( int ) );
  6674. bool bFlashlightNoLambert = GetData<int>( pCmdBuf + 10 * sizeof( int ) ) != 0;
  6675. bool bSinglePassFlashlight = GetData<int>( pCmdBuf + 11 * sizeof( int ) ) != 0;
  6676. pCmdBuf += 12 * sizeof( int );
  6677. ShaderAPITextureHandle_t hTexture = g_pShaderUtil->GetShaderAPITextureBindHandle( m_FlashlightState.m_pSpotlightTexture, m_FlashlightState.m_nSpotlightTextureFrame, 0 );
  6678. BindTexture( (Sampler_t)nLightSampler, TEXTURE_BINDFLAGS_SRGBREAD, hTexture ); // !!!BUG!!!srgb or not?
  6679. SetPixelShaderConstantInternal( nAttenConst, m_pFlashlightAtten, 1, false );
  6680. SetPixelShaderConstantInternal( nOriginConst, m_pFlashlightPos, 1, false );
  6681. m_pFlashlightColor[3] = bFlashlightNoLambert ? 2.0f : 0.0f; // This will be added to N.L before saturate to force a 1.0 N.L term
  6682. // DX10 hardware and single pass flashlight require a hack scalar since the flashlight is added in linear space
  6683. float flashlightColor[4] = { m_pFlashlightColor[0], m_pFlashlightColor[1], m_pFlashlightColor[2], m_pFlashlightColor[3] };
  6684. if ( ( g_pHardwareConfig->UsesSRGBCorrectBlending() ) || ( bSinglePassFlashlight ) )
  6685. {
  6686. // Magic number that works well on the 360 and NVIDIA 8800
  6687. flashlightColor[0] *= 2.5f;
  6688. flashlightColor[1] *= 2.5f;
  6689. flashlightColor[2] *= 2.5f;
  6690. }
  6691. SetPixelShaderConstantInternal( nColorConst, flashlightColor, 1, false );
  6692. if ( nWorldToTextureConstant >= 0 )
  6693. {
  6694. SetPixelShaderConstantInternal( nWorldToTextureConstant, m_FlashlightWorldToTexture.Base(), 4, false );
  6695. }
  6696. BindStandardTexture( (Sampler_t)nShadowNoiseSampler, TEXTURE_BINDFLAGS_NONE, TEXTURE_SHADOW_NOISE_2D );
  6697. if( m_pFlashlightDepthTexture && m_FlashlightState.m_bEnableShadows && ShaderUtil()->GetConfig().ShadowDepthTexture() )
  6698. {
  6699. ShaderAPITextureHandle_t hDepthTexture = g_pShaderUtil->GetShaderAPITextureBindHandle( m_pFlashlightDepthTexture, 0, 0 );
  6700. BindTexture( (Sampler_t)nDepthSampler, TEXTURE_BINDFLAGS_SHADOWDEPTH, hDepthTexture );
  6701. SetPixelShaderConstantInternal( nDepthTweakConst, m_pFlashlightTweaks, 1, false );
  6702. // Dimensions of screen, used for screen-space noise map sampling
  6703. float vScreenScale[4] = {1280.0f / 32.0f, 720.0f / 32.0f, 0, 0};
  6704. int nWidth, nHeight;
  6705. BaseClass::GetBackBufferDimensions( nWidth, nHeight );
  6706. int nTexWidth, nTexHeight;
  6707. GetStandardTextureDimensions( &nTexWidth, &nTexHeight, TEXTURE_SHADOW_NOISE_2D );
  6708. vScreenScale[0] = (float) nWidth / nTexWidth;
  6709. vScreenScale[1] = (float) nHeight / nTexHeight;
  6710. vScreenScale[2] = 1.0f / m_FlashlightState.m_flShadowMapResolution;
  6711. vScreenScale[3] = 2.0f / m_FlashlightState.m_flShadowMapResolution;
  6712. SetPixelShaderConstantInternal( nScreenScaleConst, vScreenScale, 1, false );
  6713. }
  6714. else
  6715. {
  6716. BindStandardTexture( (Sampler_t)nDepthSampler, TEXTURE_BINDFLAGS_NONE, TEXTURE_WHITE );
  6717. }
  6718. if ( IsX360() )
  6719. {
  6720. SetBooleanPixelShaderConstant( 0, &m_FlashlightState.m_nShadowQuality, 1 );
  6721. }
  6722. break;
  6723. }
  6724. case CBCMD_SET_PIXEL_SHADER_UBERLIGHT_STATE:
  6725. {
  6726. int iEdge0Const = GetData<int>( pCmdBuf + sizeof( int ) );
  6727. int iEdge1Const = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
  6728. int iEdgeOOWConst = GetData<int>( pCmdBuf + 3 * sizeof( int ) );
  6729. int iShearRoundConst = GetData<int>( pCmdBuf + 4 * sizeof( int ) );
  6730. int iAABBConst = GetData<int>( pCmdBuf + 5 * sizeof( int ) );
  6731. int iWorldToLightConst = GetData<int>( pCmdBuf + 6 * sizeof( int ) );
  6732. pCmdBuf += 7 * sizeof( int );
  6733. SetPixelShaderConstantInternal( iEdge0Const, m_UberlightRenderState.m_vSmoothEdge0.Base(), 1, false );
  6734. SetPixelShaderConstantInternal( iEdge1Const, m_UberlightRenderState.m_vSmoothEdge1.Base(), 1, false );
  6735. SetPixelShaderConstantInternal( iEdgeOOWConst, m_UberlightRenderState.m_vSmoothOneOverW.Base(), 1, false );
  6736. SetPixelShaderConstantInternal( iShearRoundConst, m_UberlightRenderState.m_vShearRound.Base(), 1, false );
  6737. SetPixelShaderConstantInternal( iAABBConst, m_UberlightRenderState.m_vaAbB.Base(), 1, false );
  6738. SetPixelShaderConstantInternal( iWorldToLightConst, m_UberlightRenderState.m_WorldToLight.Base(), 4, false );
  6739. break;
  6740. }
  6741. #ifndef NDEBUG
  6742. default:
  6743. Assert(0);
  6744. break;
  6745. #endif
  6746. }
  6747. pLastCmd = pCmd;
  6748. }
  6749. }
  6750. #else
  6751. void CShaderAPIDx8::ExecuteCommandBuffer( uint8 *pCmdBuf )
  6752. {
  6753. uint8 *pReturnStack[20];
  6754. uint8 **pSP = &pReturnStack[ARRAYSIZE(pReturnStack)];
  6755. uint8 *pLastCmd;
  6756. for(;;)
  6757. {
  6758. uint8 *pCmd=pCmdBuf;
  6759. int nCmd = GetData<int>( pCmdBuf );
  6760. switch( nCmd )
  6761. {
  6762. case CBCMD_END:
  6763. {
  6764. if ( pSP == &pReturnStack[ARRAYSIZE(pReturnStack)] )
  6765. return;
  6766. else
  6767. {
  6768. // pop pc
  6769. pCmdBuf = *( pSP ++ );
  6770. break;
  6771. }
  6772. }
  6773. case CBCMD_JUMP:
  6774. pCmdBuf = GetData<uint8 *>( pCmdBuf + sizeof( int ) );
  6775. break;
  6776. case CBCMD_JSR:
  6777. {
  6778. Assert( pSP > &(pReturnStack[0] ) );
  6779. // *(--pSP ) = pCmdBuf + sizeof( int ) + sizeof( uint8 *);
  6780. // pCmdBuf = GetData<uint8 *>( pCmdBuf + sizeof( int ) );
  6781. ExecuteCommandBuffer( GetData<uint8 *>( pCmdBuf + sizeof( int ) ) );
  6782. pCmdBuf = pCmdBuf + sizeof( int ) + sizeof( uint8 *);
  6783. break;
  6784. }
  6785. case CBCMD_SET_PIXEL_SHADER_FLOAT_CONST:
  6786. {
  6787. int nStartConst = GetData<int>( pCmdBuf + sizeof( int ) );
  6788. int nNumConsts = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
  6789. float const *pValues = reinterpret_cast< float const *> ( pCmdBuf + 3 * sizeof( int ) );
  6790. pCmdBuf += nNumConsts * 4 * sizeof( float ) + 3 * sizeof( int );
  6791. SetPixelShaderConstantInternal( nStartConst, pValues, nNumConsts, false );
  6792. break;
  6793. }
  6794. case CBCMD_SETPIXELSHADERFOGPARAMS:
  6795. {
  6796. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  6797. pCmdBuf += 2 * sizeof( int );
  6798. SetPixelShaderFogParams( nReg ); // !! speed fixme
  6799. break;
  6800. }
  6801. case CBCMD_STORE_EYE_POS_IN_PSCONST:
  6802. {
  6803. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  6804. float flWValue = GetData<float>( pCmdBuf + 2 * sizeof( int ) );
  6805. pCmdBuf += 2 * sizeof( int ) + sizeof( float );
  6806. Vector4D vecValue( m_WorldSpaceCameraPosition.x, m_WorldSpaceCameraPosition.y, m_WorldSpaceCameraPosition.z, flWValue );
  6807. SetPixelShaderConstantInternal( nReg, vecValue.Base(), 1, false );
  6808. break;
  6809. }
  6810. case CBCMD_SET_DEPTH_FEATHERING_CONST:
  6811. {
  6812. int nConst = GetData<int>( pCmdBuf + sizeof( int ) );
  6813. float fDepthBlendScale = GetData<float>( pCmdBuf + 2 * sizeof( int ) );
  6814. pCmdBuf += 2 * sizeof( int ) + sizeof( float );
  6815. SetDepthFeatheringShaderConstants( nConst, fDepthBlendScale );
  6816. break;
  6817. }
  6818. case CBCMD_SET_VERTEX_SHADER_FLOAT_CONST:
  6819. {
  6820. int nStartConst = GetData<int>( pCmdBuf + sizeof( int ) );
  6821. int nNumConsts = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
  6822. float const *pValues = reinterpret_cast< float const *> ( pCmdBuf + 3 * sizeof( int ) );
  6823. pCmdBuf += nNumConsts * 4 * sizeof( float ) + 3 * sizeof( int );
  6824. SetVertexShaderConstantInternal( nStartConst, pValues, nNumConsts, false );
  6825. break;
  6826. }
  6827. case CBCMD_BIND_STANDARD_TEXTURE:
  6828. {
  6829. int nSampler = GetData<int>( pCmdBuf + sizeof( int ) );
  6830. int nBindFlags = ( nSampler & TEXTURE_BINDFLAGS_VALID_MASK );
  6831. nSampler &= ( MAX_SAMPLERS - 1 );
  6832. int nTextureID = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
  6833. pCmdBuf += 3 * sizeof( int );
  6834. BindStandardTexture( (Sampler_t)nSampler, ( TextureBindFlags_t ) nBindFlags, (StandardTextureId_t )nTextureID );
  6835. break;
  6836. }
  6837. case CBCMD_BIND_SHADERAPI_TEXTURE_HANDLE:
  6838. {
  6839. int nSampler = GetData<int>( pCmdBuf + sizeof( int ) );
  6840. int nBindFlags = ( nSampler & TEXTURE_BINDFLAGS_VALID_MASK );
  6841. nSampler &= ( MAX_SAMPLERS - 1 );
  6842. ShaderAPITextureHandle_t hTexture = GetData<ShaderAPITextureHandle_t>( pCmdBuf + 2 * sizeof( int ) );
  6843. Assert( hTexture != INVALID_SHADERAPI_TEXTURE_HANDLE );
  6844. pCmdBuf += 2 * sizeof( int ) + sizeof( ShaderAPITextureHandle_t );
  6845. BindTexture( (Sampler_t) nSampler, ( TextureBindFlags_t ) nBindFlags, hTexture );
  6846. break;
  6847. }
  6848. case CBCMD_SET_PSHINDEX:
  6849. {
  6850. int nIdx = GetData<int>( pCmdBuf + sizeof( int ) );
  6851. ShaderManager()->SetPixelShaderIndex( nIdx );
  6852. pCmdBuf += 2 * sizeof( int );
  6853. break;
  6854. }
  6855. case CBCMD_SET_VSHINDEX:
  6856. {
  6857. int nIdx = GetData<int>( pCmdBuf + sizeof( int ) );
  6858. ShaderManager()->SetVertexShaderIndex( nIdx );
  6859. pCmdBuf += 2 * sizeof( int );
  6860. break;
  6861. }
  6862. case CBCMD_SET_VERTEX_SHADER_FLASHLIGHT_STATE:
  6863. {
  6864. int nStartConst = GetData<int>( pCmdBuf + sizeof( int ) );
  6865. SetVertexShaderConstantInternal( nStartConst, m_FlashlightWorldToTexture.Base(), 4, false );
  6866. pCmdBuf += 2 * sizeof( int );
  6867. break;
  6868. }
  6869. case CBCMD_SET_VERTEX_SHADER_NEARZFARZ_STATE:
  6870. {
  6871. int nStartConst = GetData<int>( pCmdBuf + sizeof( int ) );
  6872. VMatrix m;
  6873. GetMatrix( MATERIAL_PROJECTION, m.m[0] );
  6874. // m[2][2] = F/(N-F) (flip sign if RH)
  6875. // m[3][2] = NF/(N-F)
  6876. float vNearFar[4];
  6877. float N = m[3][2] / m[2][2];
  6878. float F = (m[3][2]*N) / (N + m[3][2]);
  6879. vNearFar[0] = N;
  6880. vNearFar[1] = F;
  6881. SetVertexShaderConstantInternal( nStartConst, vNearFar, 1, false );
  6882. pCmdBuf += 2 * sizeof( int );
  6883. break;
  6884. }
  6885. case CBCMD_SET_PIXEL_SHADER_FLASHLIGHT_STATE:
  6886. {
  6887. int nLightSampler = GetData<int>( pCmdBuf + sizeof( int ) );
  6888. int nDepthSampler = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
  6889. int nShadowNoiseSampler = GetData<int>( pCmdBuf + 3 * sizeof( int ) );
  6890. int nColorConst = GetData<int>( pCmdBuf + 4 * sizeof( int ) );
  6891. int nAttenConst = GetData<int>( pCmdBuf + 5 * sizeof( int ) );
  6892. int nOriginConst = GetData<int>( pCmdBuf + 6 * sizeof( int ) );
  6893. int nDepthTweakConst = GetData<int>( pCmdBuf + 7 * sizeof( int ) );
  6894. int nScreenScaleConst = GetData<int>( pCmdBuf + 8 * sizeof( int ) );
  6895. int nWorldToTextureConstant = GetData<int>( pCmdBuf + 9 * sizeof( int ) );
  6896. bool bFlashlightNoLambert = GetData<int>( pCmdBuf + 10 * sizeof( int ) ) != 0;
  6897. bool bSinglePassFlashlight = GetData<int>( pCmdBuf + 11 * sizeof( int ) ) != 0;
  6898. pCmdBuf += 12 * sizeof( int );
  6899. ShaderAPITextureHandle_t hTexture = g_pShaderUtil->GetShaderAPITextureBindHandle( m_FlashlightState.m_pSpotlightTexture, m_FlashlightState.m_nSpotlightTextureFrame, 0 );
  6900. BindTexture( (Sampler_t)nLightSampler, TEXTURE_BINDFLAGS_SRGBREAD, hTexture ); // !!!BUG!!!srgb or not?
  6901. SetPixelShaderConstantInternal( nAttenConst, m_pFlashlightAtten, 1, false );
  6902. SetPixelShaderConstantInternal( nOriginConst, m_pFlashlightPos, 1, false );
  6903. m_pFlashlightColor[3] = bFlashlightNoLambert ? 2.0f : 0.0f; // This will be added to N.L before saturate to force a 1.0 N.L term
  6904. // DX10 hardware and single pass flashlight require a hack scalar since the flashlight is added in linear space
  6905. float flashlightColor[4] = { m_pFlashlightColor[0], m_pFlashlightColor[1], m_pFlashlightColor[2], m_pFlashlightColor[3] };
  6906. if ( ( g_pHardwareConfig->UsesSRGBCorrectBlending() ) || ( bSinglePassFlashlight ) )
  6907. {
  6908. // Magic number that works well on the 360 and NVIDIA 8800
  6909. flashlightColor[0] *= 2.5f;
  6910. flashlightColor[1] *= 2.5f;
  6911. flashlightColor[2] *= 2.5f;
  6912. }
  6913. SetPixelShaderConstantInternal( nColorConst, flashlightColor, 1, false );
  6914. if ( nWorldToTextureConstant >= 0 )
  6915. {
  6916. SetPixelShaderConstantInternal( nWorldToTextureConstant, m_FlashlightWorldToTexture.Base(), 4, false );
  6917. }
  6918. BindStandardTexture( (Sampler_t)nShadowNoiseSampler, TEXTURE_BINDFLAGS_NONE, TEXTURE_SHADOW_NOISE_2D );
  6919. if( m_pFlashlightDepthTexture && m_FlashlightState.m_bEnableShadows && ShaderUtil()->GetConfig().ShadowDepthTexture() )
  6920. {
  6921. ShaderAPITextureHandle_t hDepthTexture = g_pShaderUtil->GetShaderAPITextureBindHandle( m_pFlashlightDepthTexture, 0, 0 );
  6922. BindTexture( (Sampler_t)nDepthSampler, TEXTURE_BINDFLAGS_SHADOWDEPTH, hDepthTexture );
  6923. SetPixelShaderConstantInternal( nDepthTweakConst, m_pFlashlightTweaks, 1, false );
  6924. // Dimensions of screen, used for screen-space noise map sampling
  6925. float vScreenScale[4] = {1280.0f / 32.0f, 720.0f / 32.0f, 0, 0};
  6926. int nWidth, nHeight;
  6927. BaseClass::GetBackBufferDimensions( nWidth, nHeight );
  6928. int nTexWidth, nTexHeight;
  6929. GetStandardTextureDimensions( &nTexWidth, &nTexHeight, TEXTURE_SHADOW_NOISE_2D );
  6930. vScreenScale[0] = (float) nWidth / nTexWidth;
  6931. vScreenScale[1] = (float) nHeight / nTexHeight;
  6932. vScreenScale[2] = 1.0f / m_FlashlightState.m_flShadowMapResolution;
  6933. vScreenScale[3] = 2.0f / m_FlashlightState.m_flShadowMapResolution;
  6934. SetPixelShaderConstantInternal( nScreenScaleConst, vScreenScale, 1, false );
  6935. }
  6936. else
  6937. {
  6938. BindStandardTexture( (Sampler_t)nDepthSampler, TEXTURE_BINDFLAGS_NONE, TEXTURE_WHITE );
  6939. }
  6940. if ( IsX360() )
  6941. {
  6942. SetBooleanPixelShaderConstant( 0, &m_FlashlightState.m_nShadowQuality, 1 );
  6943. }
  6944. break;
  6945. }
  6946. case CBCMD_SET_PIXEL_SHADER_UBERLIGHT_STATE:
  6947. {
  6948. int iEdge0Const = GetData<int>( pCmdBuf + sizeof( int ) );
  6949. int iEdge1Const = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
  6950. int iEdgeOOWConst = GetData<int>( pCmdBuf + 3 * sizeof( int ) );
  6951. int iShearRoundConst = GetData<int>( pCmdBuf + 4 * sizeof( int ) );
  6952. int iAABBConst = GetData<int>( pCmdBuf + 5 * sizeof( int ) );
  6953. int iWorldToLightConst = GetData<int>( pCmdBuf + 6 * sizeof( int ) );
  6954. pCmdBuf += 7 * sizeof( int );
  6955. SetPixelShaderConstantInternal( iEdge0Const, m_UberlightRenderState.m_vSmoothEdge0.Base(), 1, false );
  6956. SetPixelShaderConstantInternal( iEdge1Const, m_UberlightRenderState.m_vSmoothEdge1.Base(), 1, false );
  6957. SetPixelShaderConstantInternal( iEdgeOOWConst, m_UberlightRenderState.m_vSmoothOneOverW.Base(), 1, false );
  6958. SetPixelShaderConstantInternal( iShearRoundConst, m_UberlightRenderState.m_vShearRound.Base(), 1, false );
  6959. SetPixelShaderConstantInternal( iAABBConst, m_UberlightRenderState.m_vaAbB.Base(), 1, false );
  6960. SetPixelShaderConstantInternal( iWorldToLightConst, m_UberlightRenderState.m_WorldToLight.Base(), 4, false );
  6961. break;
  6962. }
  6963. #ifndef NDEBUG
  6964. default:
  6965. Assert(0);
  6966. break;
  6967. #endif
  6968. }
  6969. pLastCmd = pCmd;
  6970. }
  6971. }
  6972. #endif
  6973. //ConVar mat_use_old_gamma( "mat_use_old_gamma", "1" );
  6974. #define USE_OLD_GAMMA ( false )
  6975. //-----------------------------------------------------------------------------
  6976. // Executes a command buffer containing per-instance data
  6977. //-----------------------------------------------------------------------------
  6978. #ifndef _PS3
  6979. void CShaderAPIDx8::ExecuteInstanceCommandBuffer( const unsigned char *pCmdBuf, int nInstanceIndex, bool bForceStateSet )
  6980. {
  6981. if ( !pCmdBuf )
  6982. return;
  6983. //SNPROF( "CShaderAPIDx8::ExecuteInstanceCommandBuffer" );
  6984. const MeshInstanceData_t &instance = m_pRenderInstances[nInstanceIndex];
  6985. CompiledLightingState_t *pCompiledState = &m_pRenderCompiledState[nInstanceIndex];
  6986. InstanceInfo_t *pInfo = &m_pRenderInstanceInfo[nInstanceIndex];
  6987. // First, deal with all env_cubemaps
  6988. if ( m_DynamicState.m_nLocalEnvCubemapSamplers )
  6989. {
  6990. ShaderAPITextureHandle_t hEnvCubemap;
  6991. if ( !instance.m_pEnvCubemap )
  6992. {
  6993. // Should only hit this codepath during fast path brush model rendering
  6994. hEnvCubemap = m_StdTextureHandles[TEXTURE_LOCAL_ENV_CUBEMAP];
  6995. }
  6996. else
  6997. {
  6998. // FIXME: Shitty! But I don't see another way to convert the ITexture
  6999. // into a ShaderAPITextureHandle_t, and we can't expose ShaderAPITextureHandle_t
  7000. // into MeshRenderData_t I don't think..?
  7001. hEnvCubemap = ShaderUtil()->GetShaderAPITextureBindHandle( (ITexture*)(instance.m_pEnvCubemap), 0, 0 );
  7002. }
  7003. int i = SHADER_SAMPLER0;
  7004. int nSamplerMask = m_DynamicState.m_nLocalEnvCubemapSamplers;
  7005. for ( i = 0; nSamplerMask; ++i, nSamplerMask >>= 1 )
  7006. {
  7007. if ( nSamplerMask & 0x1 )
  7008. {
  7009. // NOTE: Don't use BindTexture here, as it will not actually do the binding
  7010. SetTextureState( (Sampler_t)i, LastSetTextureBindFlags( i ), hEnvCubemap, true );
  7011. }
  7012. }
  7013. }
  7014. // Next, deal with the lightmap
  7015. if ( instance.m_nLightmapPageId != MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID )
  7016. {
  7017. if ( m_DynamicState.m_nLightmapSamplers )
  7018. {
  7019. // FIXME: Shitty! But I don't see another way to convert the ITexture
  7020. // into a ShaderAPITextureHandle_t, and we can't expose ShaderAPITextureHandle_t
  7021. // into MeshRenderData_t I don't think..?
  7022. ShaderAPITextureHandle_t hLightmap = ShaderUtil()->GetLightmapTexture( instance.m_nLightmapPageId );
  7023. int i = SHADER_SAMPLER0;
  7024. int nSamplerMask = m_DynamicState.m_nLightmapSamplers;
  7025. for ( i = 0; nSamplerMask; ++i, nSamplerMask >>= 1 )
  7026. {
  7027. if ( nSamplerMask & 0x1 )
  7028. {
  7029. // NOTE: Don't use BindTexture here, as it will not actually do the binding
  7030. SetTextureState( (Sampler_t)i, LastSetTextureBindFlags( i ), hLightmap, true );
  7031. }
  7032. }
  7033. }
  7034. if ( m_DynamicState.m_nPaintmapSamplers )
  7035. {
  7036. // FIXME: Shitty! But I don't see another way to convert the ITexture
  7037. // into a ShaderAPITextureHandle_t, and we can't expose ShaderAPITextureHandle_t
  7038. // into MeshRenderData_t I don't think..?
  7039. ShaderAPITextureHandle_t hPaintmap = ShaderUtil()->GetPaintmapTexture( instance.m_nLightmapPageId );
  7040. int i = SHADER_SAMPLER0;
  7041. int nSamplerMask = m_DynamicState.m_nPaintmapSamplers;
  7042. for ( i = 0; nSamplerMask; ++i, nSamplerMask >>= 1 )
  7043. {
  7044. if ( nSamplerMask & 0x1 )
  7045. {
  7046. // NOTE: Don't use BindTexture here, as it will not actually do the binding
  7047. SetTextureState( (Sampler_t)i, LastSetTextureBindFlags( i ), hPaintmap, true );
  7048. }
  7049. }
  7050. }
  7051. }
  7052. // Next, deal with stencil state
  7053. if ( instance.m_pStencilState )
  7054. {
  7055. SetStencilStateInternal( *instance.m_pStencilState );
  7056. m_bRenderHasSetStencil = true;
  7057. }
  7058. else if ( m_bRenderHasSetStencil )
  7059. {
  7060. // If we've set the stencil state at any point, but this
  7061. // instance has a NULL stencil state, reset to initial state
  7062. SetStencilStateInternal( m_RenderInitialStencilState );
  7063. m_bRenderHasSetStencil = false;
  7064. }
  7065. MaterialSystem_Config_t &config = ShaderUtil()->GetConfig();
  7066. const unsigned char *pReturnStack[20];
  7067. const unsigned char **pSP = &pReturnStack[ARRAYSIZE(pReturnStack)];
  7068. static const unsigned char kInitialCmdString[] = "No Prev Cmd";
  7069. const unsigned char *pLastCmd = kInitialCmdString;
  7070. bool bConstantsChanged = false;
  7071. #ifdef _DEBUG
  7072. uint32 nEncounteredCmd = 0;
  7073. #endif
  7074. const unsigned char *pOrigCmd = pCmdBuf;
  7075. for(;;)
  7076. {
  7077. const unsigned char *pCmd=pCmdBuf;
  7078. int nCmd = GetData<int>( pCmdBuf );
  7079. #ifdef _DEBUG
  7080. if ( ( nCmd > CBICMD_JSR ) && ( nEncounteredCmd & ( 1 << nCmd ) ) )
  7081. {
  7082. Warning( "Perf warning: Multiple identical commands (%d) in the per-instance command buffer!\n", nCmd );
  7083. }
  7084. nEncounteredCmd |= 1 << nCmd;
  7085. #endif
  7086. switch( nCmd )
  7087. {
  7088. case CBICMD_END:
  7089. {
  7090. if ( pSP == &pReturnStack[ARRAYSIZE(pReturnStack)] )
  7091. {
  7092. if ( bConstantsChanged )
  7093. {
  7094. NotifyShaderConstantsChangedInRenderPass();
  7095. }
  7096. return;
  7097. }
  7098. // pop pc
  7099. pCmdBuf = *( pSP ++ );
  7100. }
  7101. break;
  7102. case CBICMD_JUMP:
  7103. pCmdBuf = GetData<const unsigned char *>( pCmdBuf + sizeof( int ) );
  7104. break;
  7105. case CBICMD_JSR:
  7106. {
  7107. Assert( pSP > &( pReturnStack[0] ) );
  7108. // *(--pSP ) = pCmdBuf + sizeof( int ) + sizeof( const unsigned char *);
  7109. // pCmdBuf = GetData<const unsigned char *>( pCmdBuf + sizeof( int ) );
  7110. ExecuteInstanceCommandBuffer( GetData<const unsigned char *>( pCmdBuf + sizeof( int ) ),
  7111. nInstanceIndex, bForceStateSet );
  7112. pCmdBuf = pCmdBuf + sizeof( int ) + sizeof( const unsigned char *);
  7113. }
  7114. break;
  7115. case CBICMD_SETSKINNINGMATRICES:
  7116. {
  7117. pCmdBuf += sizeof( int );
  7118. if ( bForceStateSet || !pInfo->m_bSetSkinConstants )
  7119. {
  7120. if ( SetSkinningMatrices( instance ) )
  7121. {
  7122. bConstantsChanged = true;
  7123. }
  7124. pInfo->m_bSetSkinConstants = true;
  7125. }
  7126. }
  7127. break;
  7128. case CBICMD_SETVERTEXSHADERLOCALLIGHTING:
  7129. {
  7130. pCmdBuf += sizeof( int );
  7131. if ( instance.m_pLightingState )
  7132. {
  7133. if ( !pInfo->m_bVertexShaderLocalLightsCompiled )
  7134. {
  7135. CompileVertexShaderLocalLights( pCompiledState, instance.m_pLightingState->m_nLocalLightCount, instance.m_pLightingState, m_DynamicState.m_ShaderLightState.m_bStaticLight && (!m_DynamicState.m_ShaderLightState.m_bStaticLightIndirectOnly) );
  7136. pInfo->m_bVertexShaderLocalLightsCompiled = true;
  7137. }
  7138. CommitVertexShaderLighting( pCompiledState );
  7139. bConstantsChanged = true;
  7140. }
  7141. }
  7142. break;
  7143. case CBICMD_SETPIXELSHADERLOCALLIGHTING:
  7144. {
  7145. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  7146. pCmdBuf += 2 * sizeof( int );
  7147. if ( instance.m_pLightingState )
  7148. {
  7149. if ( !pInfo->m_bPixelShaderLocalLightsCompiled )
  7150. {
  7151. CompilePixelShaderLocalLights( pCompiledState, instance.m_pLightingState->m_nLocalLightCount, instance.m_pLightingState, m_DynamicState.m_ShaderLightState.m_bStaticLight && (!m_DynamicState.m_ShaderLightState.m_bStaticLightIndirectOnly) );
  7152. pInfo->m_bPixelShaderLocalLightsCompiled = true;
  7153. }
  7154. CommitPixelShaderLighting( nReg, pCompiledState );
  7155. bConstantsChanged = true;
  7156. }
  7157. }
  7158. break;
  7159. case CBICMD_SETPIXELSHADERAMBIENTLIGHTCUBE:
  7160. {
  7161. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  7162. pCmdBuf += 2 * sizeof( int );
  7163. if ( instance.m_pLightingState )
  7164. {
  7165. if ( !pInfo->m_bAmbientCubeCompiled )
  7166. {
  7167. CompileAmbientCube( pCompiledState, instance.m_pLightingState->m_nLocalLightCount, instance.m_pLightingState );
  7168. pInfo->m_bAmbientCubeCompiled = true;
  7169. }
  7170. SetPixelShaderStateAmbientLightCube( nReg, pCompiledState );
  7171. bConstantsChanged = true;
  7172. }
  7173. }
  7174. break;
  7175. case CBICMD_SETVERTEXSHADERAMBIENTLIGHTCUBE:
  7176. {
  7177. pCmdBuf += sizeof( int );
  7178. if ( instance.m_pLightingState )
  7179. {
  7180. if ( !pInfo->m_bAmbientCubeCompiled )
  7181. {
  7182. CompileAmbientCube( pCompiledState, instance.m_pLightingState->m_nLocalLightCount, instance.m_pLightingState );
  7183. pInfo->m_bAmbientCubeCompiled = true;
  7184. }
  7185. SetVertexShaderStateAmbientLightCube( VERTEX_SHADER_AMBIENT_LIGHT, pCompiledState );
  7186. bConstantsChanged = true;
  7187. }
  7188. }
  7189. break;
  7190. case CBICMD_SETPIXELSHADERAMBIENTLIGHTCUBELUMINANCE:
  7191. {
  7192. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  7193. pCmdBuf += 2 * sizeof( int );
  7194. float flLuminance = GetAmbientLightCubeLuminance( instance.m_pLightingState );
  7195. flLuminance = clamp( flLuminance, 0.0f, 1.0f );
  7196. Vector4D psReg( flLuminance, flLuminance, flLuminance, flLuminance );
  7197. SetPixelShaderConstantInternal( nReg, psReg.Base(), 1, false );
  7198. }
  7199. break;
  7200. case CBICMD_SETPIXELSHADERGLINTDAMPING:
  7201. {
  7202. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  7203. pCmdBuf += 2 * sizeof( int );
  7204. float fGlintDamping = GetAmbientLightCubeLuminance( instance.m_pLightingState );
  7205. // Get luminance of ambient cube and saturate it
  7206. fGlintDamping = clamp( fGlintDamping, 0.0f, 1.0f );
  7207. const float fDimGlint = 0.01f;
  7208. // Remap so that glint damping smooth steps to zero for low luminances
  7209. if ( fGlintDamping > fDimGlint )
  7210. fGlintDamping = 1.0f;
  7211. else
  7212. fGlintDamping *= SimpleSplineRemapVal( fGlintDamping, 0.0f, fDimGlint, 0.0f, 1.0f );
  7213. Vector4D psReg( fGlintDamping, fGlintDamping, fGlintDamping, fGlintDamping );
  7214. SetPixelShaderConstantInternal( nReg, psReg.Base(), 1, false );
  7215. }
  7216. break;
  7217. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARCOLORSPACE:
  7218. {
  7219. // Skip the command.
  7220. pCmdBuf += sizeof( int );
  7221. // Read the register number that we want to write the colormodulation value into.
  7222. int nReg = GetData<int>( pCmdBuf );
  7223. pCmdBuf += sizeof( int ); // skip register
  7224. if ( config.nFullbright != 2 )
  7225. {
  7226. if ( USE_OLD_GAMMA )
  7227. {
  7228. // Read the material-level gamma color scale ($color2)
  7229. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  7230. // Get the per-model-instance diffuse modulation
  7231. const Vector4D &srcColor = instance.m_DiffuseModulation;
  7232. Vector4D color;
  7233. color[0] = srcColor[0] * vSrcColor2[0];
  7234. color[1] = srcColor[1] * vSrcColor2[1];
  7235. color[2] = srcColor[2] * vSrcColor2[2];
  7236. color[3] = srcColor[3];
  7237. color[0] = color[0] > 1.0f ? color[0] : GammaToLinear( color[0] );
  7238. color[1] = color[1] > 1.0f ? color[1] : GammaToLinear( color[1] );
  7239. color[2] = color[2] > 1.0f ? color[2] : GammaToLinear( color[2] );
  7240. SetPixelShaderConstantInternal( nReg, color.Base() );
  7241. }
  7242. else
  7243. {
  7244. // Read the material-level gamma color scale ($color2)
  7245. fltx4 fl4DiffuseModulation = LoadUnalignedSIMD( &instance.m_DiffuseModulation );
  7246. fltx4 fl4Color = GammaToLinearExtendedSIMD( MulSIMD( LoadUnalignedSIMD( pCmdBuf ),fl4DiffuseModulation ) );
  7247. // restore alpha
  7248. fl4Color = SetWSIMD( fl4Color, fl4DiffuseModulation );
  7249. SetPixelShaderConstantInternal( nReg, (float const * ) &fl4Color );
  7250. }
  7251. }
  7252. else
  7253. {
  7254. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  7255. SetPixelShaderConstantInternal( nReg, white.Base() );
  7256. }
  7257. pCmdBuf += sizeof( Vector4D ); // skip vSrcColor2 Vector
  7258. }
  7259. break;
  7260. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE:
  7261. {
  7262. // Skip the command.
  7263. pCmdBuf += sizeof( int );
  7264. // Read the register number that we want to write the colormodulation value into.
  7265. int nReg = GetData<int>( pCmdBuf );
  7266. pCmdBuf += sizeof( int ); // skip register
  7267. // Read the material-level gamma color scale ($color2)
  7268. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  7269. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  7270. if ( config.nFullbright != 2 )
  7271. {
  7272. // Get the per-model-instance diffuse modulation
  7273. const Vector4D &srcColor = instance.m_DiffuseModulation;
  7274. Vector4D color;
  7275. color[0] = srcColor[0] * vSrcColor2[0];
  7276. color[1] = srcColor[1] * vSrcColor2[1];
  7277. color[2] = srcColor[2] * vSrcColor2[2];
  7278. color[3] = srcColor[3];
  7279. SetPixelShaderConstantInternal( nReg, color.Base() );
  7280. }
  7281. else
  7282. {
  7283. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  7284. SetPixelShaderConstantInternal( nReg, white.Base() );
  7285. }
  7286. }
  7287. break;
  7288. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_IDENTITY:
  7289. {
  7290. // Skip the command.
  7291. pCmdBuf += sizeof( int );
  7292. // Read the register number that we want to write the colormodulation value into.
  7293. int nReg = GetData<int>( pCmdBuf );
  7294. pCmdBuf += sizeof( int ); // skip register
  7295. Vector4D color( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  7296. SetPixelShaderConstantInternal( nReg, color.Base() );
  7297. }
  7298. break;
  7299. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARCOLORSPACE_LINEARSCALE:
  7300. {
  7301. // Skip the command.
  7302. pCmdBuf += sizeof( int );
  7303. // Read the register number that we want to write the colormodulation value into.
  7304. int nReg = GetData<int>( pCmdBuf );
  7305. pCmdBuf += sizeof( int ); // skip register
  7306. if ( config.nFullbright != 2 )
  7307. {
  7308. // Read the material-level gamma color scale ($color2)
  7309. if ( USE_OLD_GAMMA )
  7310. {
  7311. Vector4D vSrcColor2 = GetData<Vector4D>( pCmdBuf );
  7312. pCmdBuf += sizeof( Vector4D ); // skip vSrcColor2 Vector
  7313. // Read the linear scale value
  7314. float scale = GetData<float>( pCmdBuf );
  7315. pCmdBuf += sizeof( float ); // skip the linear scale value
  7316. // Get the per-model-instance diffuse modulation
  7317. const Vector4D &srcColor = instance.m_DiffuseModulation;
  7318. Vector4D color;
  7319. color[0] = srcColor[0] * vSrcColor2[0];
  7320. color[1] = srcColor[1] * vSrcColor2[1];
  7321. color[2] = srcColor[2] * vSrcColor2[2];
  7322. color[3] = srcColor[3];
  7323. color[0] = ( color[0] > 1.0f ? color[0] : GammaToLinear( color[0] ) ) * scale;
  7324. color[1] = ( color[1] > 1.0f ? color[1] : GammaToLinear( color[1] ) ) * scale;
  7325. color[2] = ( color[2] > 1.0f ? color[2] : GammaToLinear( color[2] ) ) * scale;
  7326. SetPixelShaderConstantInternal( nReg, color.Base() );
  7327. }
  7328. else
  7329. {
  7330. fltx4 fl4SrcColor2 = LoadUnaligned3SIMD( pCmdBuf );
  7331. pCmdBuf += sizeof( Vector4D );
  7332. float scale = GetData<float>( pCmdBuf );
  7333. pCmdBuf += sizeof( float ); // skip the linear scale value
  7334. fltx4 fl4Scale = ReplicateX4( scale );
  7335. fltx4 fl4SrcColor = LoadUnalignedSIMD( &instance.m_DiffuseModulation );
  7336. fl4SrcColor2 = MulSIMD( GammaToLinearExtendedSIMD( MulSIMD( fl4SrcColor2, fl4SrcColor ) ), fl4Scale );
  7337. fl4SrcColor2 = SetWSIMD( fl4SrcColor2, fl4SrcColor ); // copy back the original unmodified alpha
  7338. SetPixelShaderConstantInternal( nReg, ( float const * ) &fl4SrcColor2 );
  7339. }
  7340. }
  7341. else
  7342. {
  7343. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  7344. SetPixelShaderConstantInternal( nReg, white.Base() );
  7345. pCmdBuf += sizeof( float ) + sizeof( Vector4D );
  7346. }
  7347. }
  7348. break;
  7349. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARSCALE:
  7350. {
  7351. // Skip the command.
  7352. pCmdBuf += sizeof( int );
  7353. // Read the register number that we want to write the colormodulation value into.
  7354. int nReg = GetData<int>( pCmdBuf );
  7355. pCmdBuf += sizeof( int ); // skip register
  7356. // Read the material-level gamma color scale ($color2)
  7357. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  7358. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  7359. // skip the pad
  7360. pCmdBuf += sizeof( float );
  7361. // Read the linear scale value
  7362. float scale = GetData<float>( pCmdBuf );
  7363. pCmdBuf += sizeof( float ); // skip the linear scale value
  7364. if (config.nFullbright != 2 )
  7365. {
  7366. // Get the per-model-instance diffuse modulation
  7367. const Vector4D &srcColor = instance.m_DiffuseModulation;
  7368. Vector4D color;
  7369. color[0] = srcColor[0] * vSrcColor2[0] * scale;
  7370. color[1] = srcColor[1] * vSrcColor2[1] * scale;
  7371. color[2] = srcColor[2] * vSrcColor2[2] * scale;
  7372. color[3] = srcColor[3];
  7373. SetPixelShaderConstantInternal( nReg, color.Base() );
  7374. }
  7375. else
  7376. {
  7377. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  7378. SetPixelShaderConstantInternal( nReg, white.Base() );
  7379. }
  7380. }
  7381. break;
  7382. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARSCALE_SCALEINW:
  7383. {
  7384. // Skip the command.
  7385. pCmdBuf += sizeof( int );
  7386. // Read the register number that we want to write the colormodulation value into.
  7387. int nReg = GetData<int>( pCmdBuf );
  7388. pCmdBuf += sizeof( int ); // skip register
  7389. // Read the material-level gamma color scale ($color2)
  7390. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  7391. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  7392. // Read the linear scale value
  7393. float scale = GetData<float>( pCmdBuf );
  7394. pCmdBuf += sizeof( float ); // skip the linear scale value
  7395. if ( config.nFullbright != 2 )
  7396. {
  7397. // Get the per-model-instance diffuse modulation
  7398. const Vector4D &srcColor = instance.m_DiffuseModulation;
  7399. Vector4D color;
  7400. color[0] = srcColor[0] * vSrcColor2[0] * scale;
  7401. color[1] = srcColor[1] * vSrcColor2[1] * scale;
  7402. color[2] = srcColor[2] * vSrcColor2[2] * scale;
  7403. color[3] = scale;
  7404. SetPixelShaderConstantInternal( nReg, color.Base() );
  7405. }
  7406. else
  7407. {
  7408. Vector4D vecScale( scale, scale, scale, scale );
  7409. SetPixelShaderConstantInternal( nReg, vecScale.Base() );
  7410. }
  7411. }
  7412. break;
  7413. case CBICMD_SETMODULATIONVERTEXSHADERDYNAMICSTATE:
  7414. {
  7415. // Skip the command.
  7416. pCmdBuf += sizeof( int );
  7417. // Read the register number that we want to write the colormodulation value into.
  7418. int nReg = GetData<int>( pCmdBuf );
  7419. pCmdBuf += sizeof( int ); // skip register
  7420. // Read the material-level gamma color scale ($color2)
  7421. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  7422. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  7423. if ( config.nFullbright != 2 )
  7424. {
  7425. // Get the per-model-instance diffuse modulation
  7426. const Vector4D &srcColor = instance.m_DiffuseModulation;
  7427. Vector4D color;
  7428. color[0] = srcColor[0] * vSrcColor2[0];
  7429. color[1] = srcColor[1] * vSrcColor2[1];
  7430. color[2] = srcColor[2] * vSrcColor2[2];
  7431. color[3] = srcColor[3];
  7432. SetVertexShaderConstantInternal( nReg, color.Base() );
  7433. }
  7434. else
  7435. {
  7436. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  7437. SetVertexShaderConstantInternal( nReg, white.Base() );
  7438. }
  7439. }
  7440. break;
  7441. case CBICMD_SETMODULATIONVERTEXSHADERDYNAMICSTATE_LINEARSCALE:
  7442. {
  7443. // Skip the command.
  7444. pCmdBuf += sizeof( int );
  7445. // Read the register number that we want to write the colormodulation value into.
  7446. int nReg = GetData<int>( pCmdBuf );
  7447. pCmdBuf += sizeof( int ); // skip register
  7448. // Read the material-level gamma color scale ($color2)
  7449. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  7450. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  7451. float flScale = GetData<float>( pCmdBuf );
  7452. pCmdBuf += sizeof( float );
  7453. if ( config.nFullbright != 2 )
  7454. {
  7455. // Get the per-model-instance diffuse modulation
  7456. const Vector4D &srcColor = instance.m_DiffuseModulation;
  7457. Vector4D color;
  7458. color[0] = srcColor[0] * vSrcColor2[0] * flScale;
  7459. color[1] = srcColor[1] * vSrcColor2[1] * flScale;
  7460. color[2] = srcColor[2] * vSrcColor2[2] * flScale;
  7461. color[3] = srcColor[3];
  7462. SetVertexShaderConstantInternal( nReg, color.Base() );
  7463. }
  7464. else
  7465. {
  7466. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  7467. SetVertexShaderConstantInternal( nReg, white.Base() );
  7468. }
  7469. }
  7470. break;
  7471. #ifndef NDEBUG
  7472. default:
  7473. Warning( " unknown instance command %d last = %d\n", nCmd, GetData<int>( pLastCmd ) );
  7474. DebuggerBreak();
  7475. break;
  7476. #endif
  7477. }
  7478. pLastCmd = pCmd;
  7479. }
  7480. }
  7481. #endif
  7482. //-----------------------------------------------------------------------------
  7483. // Sets the boolean registers for pixel shader control flow
  7484. //-----------------------------------------------------------------------------
  7485. void CShaderAPIDx8::SetBooleanPixelShaderConstant( int var, int const* pVec, int numBools, bool bForce )
  7486. {
  7487. Assert( pVec );
  7488. Assert( var + numBools <= g_pHardwareConfig->NumBooleanPixelShaderConstants() );
  7489. if ( IsPC() && !bForce && memcmp( pVec, &m_DesiredState.m_pBooleanPixelShaderConstant[var], numBools * sizeof( BOOL ) ) == 0 )
  7490. {
  7491. return;
  7492. }
  7493. if ( IsPC() || IsPS3() )
  7494. {
  7495. Dx9Device()->SetPixelShaderConstantB( var, pVec, numBools );
  7496. memcpy( &m_DynamicState.m_pBooleanPixelShaderConstant[var], pVec, numBools * sizeof(BOOL) );
  7497. }
  7498. if ( IsX360() )
  7499. {
  7500. if ( !IsGPUOwnSupported() || !m_bGPUOwned )
  7501. {
  7502. Dx9Device()->SetPixelShaderConstantB( var, pVec, numBools );
  7503. memcpy( &m_DynamicState.m_pBooleanPixelShaderConstant[var], pVec, numBools * sizeof(BOOL) );
  7504. }
  7505. else if ( var + numBools > m_MaxBooleanPixelShaderConstant )
  7506. {
  7507. m_MaxBooleanPixelShaderConstant = var + numBools;
  7508. Assert( m_MaxBooleanPixelShaderConstant <= 16 );
  7509. }
  7510. }
  7511. memcpy( &m_DesiredState.m_pBooleanPixelShaderConstant[var], pVec, numBools * sizeof(BOOL) );
  7512. }
  7513. //-----------------------------------------------------------------------------
  7514. // Sets the integer registers for pixel shader control flow
  7515. //-----------------------------------------------------------------------------
  7516. void CShaderAPIDx8::SetIntegerPixelShaderConstant( int var, int const* pVec, int numIntVecs, bool bForce )
  7517. {
  7518. Assert( pVec );
  7519. Assert( var + numIntVecs <= g_pHardwareConfig->NumIntegerPixelShaderConstants() );
  7520. if ( IsPC() && !bForce && memcmp( pVec, &m_DesiredState.m_pIntegerPixelShaderConstant[var], numIntVecs * sizeof( IntVector4D ) ) == 0 )
  7521. {
  7522. return;
  7523. }
  7524. if ( IsPC() || IsPS3() )
  7525. {
  7526. Dx9Device()->SetPixelShaderConstantI( var, pVec, numIntVecs );
  7527. memcpy( &m_DynamicState.m_pIntegerPixelShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
  7528. }
  7529. if ( IsX360() )
  7530. {
  7531. if ( !IsGPUOwnSupported() || !m_bGPUOwned )
  7532. {
  7533. Dx9Device()->SetPixelShaderConstantI( var, pVec, numIntVecs );
  7534. memcpy( &m_DynamicState.m_pIntegerPixelShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
  7535. }
  7536. else if ( var + numIntVecs > m_MaxIntegerPixelShaderConstant )
  7537. {
  7538. m_MaxIntegerPixelShaderConstant = var + numIntVecs;
  7539. Assert( m_MaxBooleanPixelShaderConstant <= 16 );
  7540. }
  7541. }
  7542. memcpy( &m_DesiredState.m_pIntegerPixelShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
  7543. }
  7544. void CShaderAPIDx8::InvalidateDelayedShaderConstants( void )
  7545. {
  7546. m_DelayedShaderConstants.Invalidate();
  7547. }
  7548. //-----------------------------------------------------------------------------
  7549. //
  7550. // Methods dealing with texture stage state
  7551. //
  7552. //-----------------------------------------------------------------------------
  7553. //-----------------------------------------------------------------------------
  7554. // Gets the texture associated with a texture state...
  7555. //-----------------------------------------------------------------------------
  7556. inline IDirect3DBaseTexture* CShaderAPIDx8::GetD3DTexture( ShaderAPITextureHandle_t hTexture )
  7557. {
  7558. if ( hTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
  7559. {
  7560. return NULL;
  7561. }
  7562. AssertValidTextureHandle( hTexture );
  7563. Texture_t& tex = GetTexture( hTexture );
  7564. if ( tex.m_NumCopies == 1 )
  7565. {
  7566. return tex.GetTexture();
  7567. }
  7568. else
  7569. {
  7570. return tex.GetTexture( tex.m_CurrentCopy );
  7571. }
  7572. }
  7573. bool CShaderAPIDx8::IsStandardTextureHandleValid( StandardTextureId_t textureId )
  7574. {
  7575. ShaderAPITextureHandle_t hTex = GetStandardTextureHandle( textureId );
  7576. if ( hTex == INVALID_SHADERAPI_TEXTURE_HANDLE )
  7577. return false;
  7578. if ( !GetD3DTexture( hTex ) )
  7579. return false;
  7580. return true;
  7581. }
  7582. inline void* CShaderAPIDx8::GetD3DTexturePtr( ShaderAPITextureHandle_t hTexture )
  7583. {
  7584. return (void *)GetD3DTexture( hTexture );
  7585. }
  7586. //-----------------------------------------------------------------------------
  7587. // Inline methods
  7588. //-----------------------------------------------------------------------------
  7589. inline ShaderAPITextureHandle_t CShaderAPIDx8::GetModifyTextureHandle() const
  7590. {
  7591. return m_ModifyTextureHandle;
  7592. }
  7593. inline IDirect3DBaseTexture* CShaderAPIDx8::GetModifyTexture()
  7594. {
  7595. return CShaderAPIDx8::GetD3DTexture( m_ModifyTextureHandle );
  7596. }
  7597. void CShaderAPIDx8::SetModifyTexture( IDirect3DBaseTexture* pTex )
  7598. {
  7599. if ( m_ModifyTextureHandle == INVALID_SHADERAPI_TEXTURE_HANDLE )
  7600. return;
  7601. Texture_t& tex = GetTexture( m_ModifyTextureHandle );
  7602. if ( tex.m_NumCopies == 1 )
  7603. {
  7604. tex.SetTexture( pTex );
  7605. }
  7606. else
  7607. {
  7608. tex.SetTexture( tex.m_CurrentCopy, pTex );
  7609. }
  7610. }
  7611. inline ShaderAPITextureHandle_t CShaderAPIDx8::GetBoundTextureBindId( Sampler_t sampler ) const
  7612. {
  7613. return SamplerState( sampler ).m_BoundTexture;
  7614. }
  7615. inline bool CShaderAPIDx8::WouldBeOverTextureLimit( ShaderAPITextureHandle_t hTexture )
  7616. {
  7617. if ( IsPC() )
  7618. {
  7619. if ( mat_texture_limit.GetInt() < 0 )
  7620. return false;
  7621. Texture_t &tex = GetTexture( hTexture );
  7622. if ( tex.m_LastBoundFrame == m_CurrentFrame )
  7623. return false;
  7624. return m_nTextureMemoryUsedLastFrame + tex.GetMemUsage() > (mat_texture_limit.GetInt() * 1024);
  7625. }
  7626. return false;
  7627. }
  7628. //-----------------------------------------------------------------------------
  7629. // Moves to head of LRU. Allocates and queues for loading if evicted. Returns
  7630. // true if texture is resident, false otherwise.
  7631. //-----------------------------------------------------------------------------
  7632. FORCEINLINE void CShaderAPIDx8::TouchTexture( Sampler_t sampler, IDirect3DBaseTexture *pD3DTexture )
  7633. {
  7634. #ifdef _X360
  7635. bool bValid = true;
  7636. if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
  7637. {
  7638. CXboxTexture *pXboxTexture = (CXboxTexture *)pD3DTexture;
  7639. if ( pXboxTexture->m_nFrameCount != m_CurrentFrame )
  7640. {
  7641. pXboxTexture->m_nFrameCount = m_CurrentFrame;
  7642. bValid = g_TextureHeap.TouchTexture( pXboxTexture );
  7643. }
  7644. else
  7645. bValid = ( pXboxTexture->m_BaseValid != 0 );
  7646. }
  7647. if ( bValid )
  7648. {
  7649. // base is valid for rendering
  7650. Dx9Device()->SetSamplerState( sampler, D3DSAMP_MAXMIPLEVEL, 0 );
  7651. }
  7652. else
  7653. {
  7654. // base is invalid for rendering
  7655. Dx9Device()->SetSamplerState( sampler, D3DSAMP_MAXMIPLEVEL, 1 );
  7656. }
  7657. #endif
  7658. }
  7659. #ifndef _PS3
  7660. #define SETSAMPLESTATEANDMIRROR( sampler, samplerState, state_type, mirror_field, value ) \
  7661. if ( samplerState.mirror_field != value ) \
  7662. { \
  7663. samplerState.mirror_field = value; \
  7664. SetSamplerState( sampler, state_type, samplerState.mirror_field ); \
  7665. }
  7666. #define SETSAMPLEADRESSSTATEANDMIRROR( sampler, samplerState, state_type, mirror_field, value ) \
  7667. if ( samplerState.mirror_field != D3DTEXTUREADDRESS(value) ) \
  7668. { \
  7669. samplerState.mirror_field = D3DTEXTUREADDRESS(value); \
  7670. SetSamplerState( sampler, state_type, samplerState.mirror_field ); \
  7671. }
  7672. #else
  7673. // No Mirroring on SPU, the redundant set sampler states are on SPU
  7674. #define SETSAMPLESTATEANDMIRROR( sampler, samplerState, state_type, mirror_field, value ) \
  7675. SetSamplerState( sampler, state_type, value );
  7676. #define SETSAMPLEADRESSSTATEANDMIRROR( sampler, samplerState, state_type, mirror_field, value ) \
  7677. SetSamplerState( sampler, state_type, D3DTEXTUREADDRESS(value) );
  7678. #endif
  7679. #ifdef _X360
  7680. const DWORD g_MapLinearToSrgbGpuFormat[] =
  7681. {
  7682. GPUTEXTUREFORMAT_1_REVERSE,
  7683. GPUTEXTUREFORMAT_1,
  7684. GPUTEXTUREFORMAT_8,
  7685. GPUTEXTUREFORMAT_1_5_5_5,
  7686. GPUTEXTUREFORMAT_5_6_5,
  7687. GPUTEXTUREFORMAT_6_5_5,
  7688. GPUTEXTUREFORMAT_8_8_8_8_AS_16_16_16_16,
  7689. GPUTEXTUREFORMAT_2_10_10_10_AS_16_16_16_16,
  7690. GPUTEXTUREFORMAT_8_A,
  7691. GPUTEXTUREFORMAT_8_B,
  7692. GPUTEXTUREFORMAT_8_8,
  7693. GPUTEXTUREFORMAT_Cr_Y1_Cb_Y0_REP,
  7694. GPUTEXTUREFORMAT_Y1_Cr_Y0_Cb_REP,
  7695. GPUTEXTUREFORMAT_16_16_EDRAM,
  7696. GPUTEXTUREFORMAT_8_8_8_8_A,
  7697. GPUTEXTUREFORMAT_4_4_4_4,
  7698. GPUTEXTUREFORMAT_10_11_11_AS_16_16_16_16,
  7699. GPUTEXTUREFORMAT_11_11_10_AS_16_16_16_16,
  7700. GPUTEXTUREFORMAT_DXT1_AS_16_16_16_16,
  7701. GPUTEXTUREFORMAT_DXT2_3_AS_16_16_16_16,
  7702. GPUTEXTUREFORMAT_DXT4_5_AS_16_16_16_16,
  7703. GPUTEXTUREFORMAT_16_16_16_16_EDRAM,
  7704. GPUTEXTUREFORMAT_24_8,
  7705. GPUTEXTUREFORMAT_24_8_FLOAT,
  7706. GPUTEXTUREFORMAT_16,
  7707. GPUTEXTUREFORMAT_16_16,
  7708. GPUTEXTUREFORMAT_16_16_16_16,
  7709. GPUTEXTUREFORMAT_16_EXPAND,
  7710. GPUTEXTUREFORMAT_16_16_EXPAND,
  7711. GPUTEXTUREFORMAT_16_16_16_16_EXPAND,
  7712. GPUTEXTUREFORMAT_16_FLOAT,
  7713. GPUTEXTUREFORMAT_16_16_FLOAT,
  7714. GPUTEXTUREFORMAT_16_16_16_16_FLOAT,
  7715. GPUTEXTUREFORMAT_32,
  7716. GPUTEXTUREFORMAT_32_32,
  7717. GPUTEXTUREFORMAT_32_32_32_32,
  7718. GPUTEXTUREFORMAT_32_FLOAT,
  7719. GPUTEXTUREFORMAT_32_32_FLOAT,
  7720. GPUTEXTUREFORMAT_32_32_32_32_FLOAT,
  7721. GPUTEXTUREFORMAT_32_AS_8,
  7722. GPUTEXTUREFORMAT_32_AS_8_8,
  7723. GPUTEXTUREFORMAT_16_MPEG,
  7724. GPUTEXTUREFORMAT_16_16_MPEG,
  7725. GPUTEXTUREFORMAT_8_INTERLACED,
  7726. GPUTEXTUREFORMAT_32_AS_8_INTERLACED,
  7727. GPUTEXTUREFORMAT_32_AS_8_8_INTERLACED,
  7728. GPUTEXTUREFORMAT_16_INTERLACED,
  7729. GPUTEXTUREFORMAT_16_MPEG_INTERLACED,
  7730. GPUTEXTUREFORMAT_16_16_MPEG_INTERLACED,
  7731. GPUTEXTUREFORMAT_DXN,
  7732. GPUTEXTUREFORMAT_8_8_8_8_AS_16_16_16_16,
  7733. GPUTEXTUREFORMAT_DXT1_AS_16_16_16_16,
  7734. GPUTEXTUREFORMAT_DXT2_3_AS_16_16_16_16,
  7735. GPUTEXTUREFORMAT_DXT4_5_AS_16_16_16_16,
  7736. GPUTEXTUREFORMAT_2_10_10_10_AS_16_16_16_16,
  7737. GPUTEXTUREFORMAT_10_11_11_AS_16_16_16_16,
  7738. GPUTEXTUREFORMAT_11_11_10_AS_16_16_16_16,
  7739. GPUTEXTUREFORMAT_32_32_32_FLOAT,
  7740. GPUTEXTUREFORMAT_DXT3A,
  7741. GPUTEXTUREFORMAT_DXT5A,
  7742. GPUTEXTUREFORMAT_CTX1,
  7743. GPUTEXTUREFORMAT_DXT3A_AS_1_1_1_1,
  7744. GPUTEXTUREFORMAT_8_8_8_8_GAMMA_EDRAM,
  7745. GPUTEXTUREFORMAT_2_10_10_10_FLOAT_EDRAM,
  7746. };
  7747. DWORD GetAs16SRGBFormatGPU( D3DFORMAT fmtBase )
  7748. {
  7749. return g_MapLinearToSrgbGpuFormat[ (fmtBase & D3DFORMAT_TEXTUREFORMAT_MASK) >> D3DFORMAT_TEXTUREFORMAT_SHIFT ];
  7750. }
  7751. void ConvertTextureToAs16SRGBFormat( D3DTexture *pTexture )
  7752. {
  7753. // First thing, mark the texture SignX, SignY and SignZ as sRGB.
  7754. pTexture->Format.SignX = GPUSIGN_GAMMA;
  7755. pTexture->Format.SignY = GPUSIGN_GAMMA;
  7756. pTexture->Format.SignZ = GPUSIGN_GAMMA;
  7757. // Get the texture format...
  7758. XGTEXTURE_DESC desc;
  7759. XGGetTextureDesc( pTexture, 0, &desc );
  7760. // ...and convert it to a "good" format (AS_16_16_16_16).
  7761. pTexture->Format.DataFormat = GetAs16SRGBFormatGPU( desc.Format );
  7762. }
  7763. ConVar r_use16bit_srgb_sampling( "r_use16bit_srgb_sampling", "1", FCVAR_CHEAT );
  7764. #endif
  7765. //--------------------------------------------------------------------------------------------------
  7766. // PS3 Texture Setting
  7767. //--------------------------------------------------------------------------------------------------
  7768. ShaderAPITextureHandle_t CShaderAPIDx8::GetStandardTextureHandle(StandardTextureId_t id)
  7769. {
  7770. ShaderAPITextureHandle_t hTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
  7771. if ( m_StdTextureHandles[id] != INVALID_SHADERAPI_TEXTURE_HANDLE )
  7772. {
  7773. hTexture = m_StdTextureHandles[id];
  7774. }
  7775. else
  7776. {
  7777. hTexture = ShaderUtil()->GetStandardTexture( id );
  7778. }
  7779. return hTexture;
  7780. }
  7781. #ifdef _PS3
  7782. void CShaderAPIDx8::GetPs3Texture(void* pPs3tex, ShaderAPITextureHandle_t hTexture )
  7783. {
  7784. CPs3BindTexture_t& ps3tex = *(CPs3BindTexture_t*)pPs3tex;
  7785. if (hTexture != INVALID_SHADERAPI_TEXTURE_HANDLE)
  7786. {
  7787. IDirect3DBaseTexture *pTexture = CShaderAPIDx8::GetD3DTexture( hTexture );
  7788. Texture_t &tex = GetTexture( hTexture );
  7789. ps3tex.m_UWrap = tex.m_UTexWrap;
  7790. ps3tex.m_VWrap = tex.m_VTexWrap;
  7791. ps3tex.m_WWrap = tex.m_WTexWrap;
  7792. ps3tex.m_minFilter = tex.m_MinFilter;
  7793. ps3tex.m_magFilter = tex.m_MagFilter;
  7794. ps3tex.m_mipFilter = tex.m_MipFilter;
  7795. ps3tex.m_nLayout = (uint32)pTexture->m_tex->m_layout;
  7796. ps3tex.m_pLmBlock = &pTexture->m_tex->m_lmBlock;
  7797. }
  7798. else
  7799. {
  7800. ps3tex.m_nLayout = 0;
  7801. }
  7802. }
  7803. void CShaderAPIDx8::GetPs3Texture(void* pPs3tex, StandardTextureId_t nTextureId )
  7804. {
  7805. CPs3BindTexture_t& ps3tex = *(CPs3BindTexture_t*)pPs3tex;
  7806. ShaderAPITextureHandle_t hTexture = GetStandardTextureHandle(nTextureId);
  7807. if (hTexture != INVALID_SHADERAPI_TEXTURE_HANDLE)
  7808. {
  7809. IDirect3DBaseTexture *pTexture = CShaderAPIDx8::GetD3DTexture( hTexture );
  7810. Texture_t &tex = GetTexture( hTexture );
  7811. ps3tex.m_UWrap = tex.m_UTexWrap;
  7812. ps3tex.m_VWrap = tex.m_VTexWrap;
  7813. ps3tex.m_WWrap = tex.m_WTexWrap;
  7814. ps3tex.m_minFilter = tex.m_MinFilter;
  7815. ps3tex.m_magFilter = tex.m_MagFilter;
  7816. ps3tex.m_mipFilter = tex.m_MipFilter;
  7817. ps3tex.m_nLayout = (uint32)pTexture->m_tex->m_layout;
  7818. ps3tex.m_pLmBlock = &pTexture->m_tex->m_lmBlock;
  7819. }
  7820. else
  7821. {
  7822. ps3tex.m_nLayout = 0;
  7823. }
  7824. }
  7825. void CShaderAPIDx8::SetTextureState( Sampler_t sampler, TextureBindFlags_t nBindFlags, ShaderAPITextureHandle_t hTexture, bool force )
  7826. {
  7827. // Get the dynamic texture info
  7828. SamplerState_t &samplerState = SamplerState( sampler );
  7829. // // Set the texture state, but only if it changes
  7830. // if ( ( samplerState.m_BoundTexture == hTexture ) && ( LastSetTextureBindFlags( sampler ) == nBindFlags ))
  7831. // return;
  7832. //
  7833. // Disabling texturing
  7834. if ( hTexture == INVALID_SHADERAPI_TEXTURE_HANDLE)
  7835. {
  7836. Dx9Device()->SetTexture( sampler, 0 );
  7837. return;
  7838. }
  7839. samplerState.m_BoundTexture = hTexture;
  7840. IDirect3DBaseTexture *pTexture = CShaderAPIDx8::GetD3DTexture( hTexture );
  7841. SetSamplerState( sampler, D3DSAMP_SRGBTEXTURE, ( nBindFlags & TEXTURE_BINDFLAGS_SRGBREAD ) != 0 );
  7842. samplerState.m_nTextureBindFlags = nBindFlags;
  7843. Dx9Device()->SetTexture( sampler, pTexture );
  7844. Texture_t &tex = GetTexture( hTexture );
  7845. SETSAMPLEADRESSSTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSU, m_UTexWrap, tex.m_UTexWrap );
  7846. SETSAMPLEADRESSSTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSV, m_VTexWrap, tex.m_VTexWrap );
  7847. SETSAMPLEADRESSSTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSW, m_WTexWrap, tex.m_WTexWrap );
  7848. const uint nNewShadowFilterState = ( nBindFlags & TEXTURE_BINDFLAGS_SHADOWDEPTH ) ? 1 : 0;
  7849. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_SHADOWFILTER, m_bShadowFilterEnable, nNewShadowFilterState );
  7850. D3DTEXTUREFILTERTYPE minFilter = D3DTEXTUREFILTERTYPE(tex.m_MinFilter);
  7851. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MINFILTER, m_MinFilter, minFilter );
  7852. D3DTEXTUREFILTERTYPE magFilter = D3DTEXTUREFILTERTYPE(tex.m_MagFilter);
  7853. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MAGFILTER, m_MagFilter, magFilter );
  7854. D3DTEXTUREFILTERTYPE mipFilter = D3DTEXTUREFILTERTYPE(tex.m_MipFilter);
  7855. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MIPFILTER, m_MipFilter, mipFilter );
  7856. }
  7857. void CShaderAPIDx8::SetTextureFilterMode( Sampler_t sampler, TextureFilterMode_t nMode )
  7858. {
  7859. SamplerState_t &samplerState = SamplerState( sampler );
  7860. D3DTEXTUREFILTERTYPE minFilter = samplerState.m_MinFilter;
  7861. D3DTEXTUREFILTERTYPE magFilter = samplerState.m_MagFilter;
  7862. D3DTEXTUREFILTERTYPE mipFilter = samplerState.m_MipFilter;
  7863. switch( nMode )
  7864. {
  7865. case TFILTER_MODE_POINTSAMPLED:
  7866. minFilter = D3DTEXF_POINT;
  7867. magFilter = D3DTEXF_POINT;
  7868. mipFilter = D3DTEXF_POINT;
  7869. break;
  7870. }
  7871. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MINFILTER, m_MinFilter, minFilter );
  7872. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MAGFILTER, m_MagFilter, magFilter );
  7873. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MIPFILTER, m_MipFilter, mipFilter );
  7874. }
  7875. void CShaderAPIDx8::BindTexture( Sampler_t sampler, TextureBindFlags_t nBindFlags, ShaderAPITextureHandle_t textureHandle )
  7876. {
  7877. //SNPROF("CShaderAPIDx8::BindTexture <><><><>");
  7878. LOCK_SHADERAPI();
  7879. SetTextureState( sampler, nBindFlags, textureHandle );
  7880. }
  7881. void CShaderAPIDx8::BindStandardTexture( Sampler_t sampler, TextureBindFlags_t nBindFlags, StandardTextureId_t id )
  7882. {
  7883. ShaderAPITextureHandle_t hTexture = GetStandardTextureHandle(id);
  7884. BindTexture( sampler, nBindFlags, hTexture );
  7885. if ((id == TEXTURE_LIGHTMAP_BUMPED) ||(id == TEXTURE_LIGHTMAP_BUMPED_FULLBRIGHT))
  7886. {
  7887. BindTexture( (Sampler_t)((int)sampler+1), nBindFlags, hTexture );
  7888. BindTexture( (Sampler_t)((int)sampler+2), nBindFlags, hTexture );
  7889. }
  7890. Assert( LastSetTextureBindFlags( sampler ) == nBindFlags );
  7891. }
  7892. void CShaderAPIDx8::ExecuteInstanceCommandBuffer( const unsigned char *pCmdBuf, int nInstanceIndex, bool bForceStateSet )
  7893. {
  7894. if ( !pCmdBuf )
  7895. return;
  7896. //SNPROF( "CShaderAPIDx8::ExecuteInstanceCommandBuffer" );
  7897. const MeshInstanceData_t &instance = m_pRenderInstances[nInstanceIndex];
  7898. CompiledLightingState_t *pCompiledState = &m_pRenderCompiledState[nInstanceIndex];
  7899. InstanceInfo_t *pInfo = &m_pRenderInstanceInfo[nInstanceIndex];
  7900. {
  7901. //
  7902. // Texture replacements for instances
  7903. //
  7904. if (IsRenderingInstances())
  7905. {
  7906. CPs3BindTexture_t tex;
  7907. ShaderAPITextureHandle_t hTexture;
  7908. // Env maps
  7909. if (instance.m_pEnvCubemap)
  7910. {
  7911. hTexture = ShaderUtil()->GetShaderAPITextureBindHandle( (ITexture*)(instance.m_pEnvCubemap), 0, 0 );
  7912. GetPs3Texture( (void*)&tex,hTexture );
  7913. gpGcmDrawState->TextureReplace(TEXTURE_LOCAL_ENV_CUBEMAP, tex);
  7914. }
  7915. // Lightmaps/paint
  7916. if (instance.m_nLightmapPageId != MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID)
  7917. {
  7918. hTexture = ShaderUtil()->GetLightmapTexture( instance.m_nLightmapPageId );
  7919. GetPs3Texture( (void*)&tex,hTexture );
  7920. gpGcmDrawState->TextureReplace(TEXTURE_LIGHTMAP, tex);
  7921. hTexture = ShaderUtil()->GetPaintmapTexture( instance.m_nLightmapPageId );
  7922. GetPs3Texture( (void*)&tex,hTexture );
  7923. gpGcmDrawState->TextureReplace(TEXTURE_PAINT, tex);
  7924. }
  7925. }
  7926. }
  7927. // Next, deal with stencil state
  7928. if ( instance.m_pStencilState )
  7929. {
  7930. SetStencilStateInternal( *instance.m_pStencilState );
  7931. m_bRenderHasSetStencil = true;
  7932. }
  7933. else if ( m_bRenderHasSetStencil )
  7934. {
  7935. // If we've set the stencil state at any point, but this
  7936. // instance has a NULL stencil state, reset to initial state
  7937. SetStencilStateInternal( m_RenderInitialStencilState );
  7938. m_bRenderHasSetStencil = false;
  7939. }
  7940. MaterialSystem_Config_t &config = ShaderUtil()->GetConfig();
  7941. const unsigned char *pReturnStack[20];
  7942. const unsigned char **pSP = &pReturnStack[ARRAYSIZE(pReturnStack)];
  7943. const unsigned char *pLastCmd;
  7944. bool bConstantsChanged = false;
  7945. #ifdef _DEBUG
  7946. uint32 nEncounteredCmd = 0;
  7947. #endif
  7948. const unsigned char *pOrigCmd = pCmdBuf;
  7949. for(;;)
  7950. {
  7951. const unsigned char *pCmd=pCmdBuf;
  7952. int nCmd = GetData<int>( pCmdBuf );
  7953. #ifdef _DEBUG
  7954. if ( ( nCmd > CBICMD_JSR ) && ( nEncounteredCmd & ( 1 << nCmd ) ) )
  7955. {
  7956. Warning( "Perf warning: Multiple identical commands (%d) in the per-instance command buffer!\n", nCmd );
  7957. }
  7958. nEncounteredCmd |= 1 << nCmd;
  7959. #endif
  7960. switch( nCmd )
  7961. {
  7962. case CBICMD_END:
  7963. {
  7964. if ( pSP == &pReturnStack[ARRAYSIZE(pReturnStack)] )
  7965. {
  7966. if ( bConstantsChanged )
  7967. {
  7968. NotifyShaderConstantsChangedInRenderPass();
  7969. }
  7970. return;
  7971. }
  7972. // pop pc
  7973. pCmdBuf = *( pSP ++ );
  7974. }
  7975. break;
  7976. case CBICMD_JUMP:
  7977. pCmdBuf = GetData<const unsigned char *>( pCmdBuf + sizeof( int ) );
  7978. break;
  7979. case CBICMD_JSR:
  7980. {
  7981. Assert( pSP > &( pReturnStack[0] ) );
  7982. // *(--pSP ) = pCmdBuf + sizeof( int ) + sizeof( const unsigned char *);
  7983. // pCmdBuf = GetData<const unsigned char *>( pCmdBuf + sizeof( int ) );
  7984. ExecuteInstanceCommandBuffer( GetData<const unsigned char *>( pCmdBuf + sizeof( int ) ),
  7985. nInstanceIndex, bForceStateSet );
  7986. pCmdBuf = pCmdBuf + sizeof( int ) + sizeof( const unsigned char *);
  7987. }
  7988. break;
  7989. case CBICMD_SETSKINNINGMATRICES:
  7990. {
  7991. pCmdBuf += sizeof( int );
  7992. if ( bForceStateSet || !pInfo->m_bSetSkinConstants )
  7993. {
  7994. if ( SetSkinningMatrices( instance ) )
  7995. {
  7996. bConstantsChanged = true;
  7997. }
  7998. pInfo->m_bSetSkinConstants = true;
  7999. }
  8000. }
  8001. break;
  8002. case CBICMD_SETVERTEXSHADERLOCALLIGHTING:
  8003. {
  8004. pCmdBuf += sizeof( int );
  8005. if ( instance.m_pLightingState )
  8006. {
  8007. if ( !pInfo->m_bVertexShaderLocalLightsCompiled )
  8008. {
  8009. CompileVertexShaderLocalLights( pCompiledState, instance.m_pLightingState->m_nLocalLightCount, instance.m_pLightingState );
  8010. pInfo->m_bVertexShaderLocalLightsCompiled = true;
  8011. }
  8012. CommitVertexShaderLighting( pCompiledState );
  8013. bConstantsChanged = true;
  8014. }
  8015. }
  8016. break;
  8017. case CBICMD_SETPIXELSHADERLOCALLIGHTING:
  8018. {
  8019. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  8020. pCmdBuf += 2 * sizeof( int );
  8021. if ( instance.m_pLightingState )
  8022. {
  8023. if ( !pInfo->m_bPixelShaderLocalLightsCompiled )
  8024. {
  8025. CompilePixelShaderLocalLights( pCompiledState, instance.m_pLightingState->m_nLocalLightCount, instance.m_pLightingState );
  8026. pInfo->m_bPixelShaderLocalLightsCompiled = true;
  8027. }
  8028. CommitPixelShaderLighting( nReg, pCompiledState );
  8029. bConstantsChanged = true;
  8030. }
  8031. }
  8032. break;
  8033. case CBICMD_SETPIXELSHADERAMBIENTLIGHTCUBE:
  8034. {
  8035. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  8036. pCmdBuf += 2 * sizeof( int );
  8037. if ( instance.m_pLightingState )
  8038. {
  8039. if ( !pInfo->m_bAmbientCubeCompiled )
  8040. {
  8041. CompileAmbientCube( pCompiledState, instance.m_pLightingState->m_nLocalLightCount, instance.m_pLightingState );
  8042. pInfo->m_bAmbientCubeCompiled = true;
  8043. }
  8044. SetPixelShaderStateAmbientLightCube( nReg, pCompiledState );
  8045. bConstantsChanged = true;
  8046. }
  8047. }
  8048. break;
  8049. case CBICMD_SETVERTEXSHADERAMBIENTLIGHTCUBE:
  8050. {
  8051. pCmdBuf += sizeof( int );
  8052. if ( instance.m_pLightingState )
  8053. {
  8054. if ( !pInfo->m_bAmbientCubeCompiled )
  8055. {
  8056. CompileAmbientCube( pCompiledState, instance.m_pLightingState->m_nLocalLightCount, instance.m_pLightingState );
  8057. pInfo->m_bAmbientCubeCompiled = true;
  8058. }
  8059. SetVertexShaderStateAmbientLightCube( VERTEX_SHADER_AMBIENT_LIGHT, pCompiledState );
  8060. bConstantsChanged = true;
  8061. }
  8062. }
  8063. break;
  8064. case CBICMD_SETPIXELSHADERAMBIENTLIGHTCUBELUMINANCE:
  8065. {
  8066. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  8067. pCmdBuf += 2 * sizeof( int );
  8068. float flLuminance = GetAmbientLightCubeLuminance( instance.m_pLightingState );
  8069. flLuminance = clamp( flLuminance, 0.0f, 1.0f );
  8070. Vector4D psReg( flLuminance, flLuminance, flLuminance, flLuminance );
  8071. SetPixelShaderConstantInternal( nReg, psReg.Base(), 1, false );
  8072. }
  8073. break;
  8074. case CBICMD_SETPIXELSHADERGLINTDAMPING:
  8075. {
  8076. int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
  8077. pCmdBuf += 2 * sizeof( int );
  8078. float fGlintDamping = GetAmbientLightCubeLuminance( instance.m_pLightingState );
  8079. // Get luminance of ambient cube and saturate it
  8080. fGlintDamping = clamp( fGlintDamping, 0.0f, 1.0f );
  8081. const float fDimGlint = 0.01f;
  8082. // Remap so that glint damping smooth steps to zero for low luminances
  8083. if ( fGlintDamping > fDimGlint )
  8084. fGlintDamping = 1.0f;
  8085. else
  8086. fGlintDamping *= SimpleSplineRemapVal( fGlintDamping, 0.0f, fDimGlint, 0.0f, 1.0f );
  8087. Vector4D psReg( fGlintDamping, fGlintDamping, fGlintDamping, fGlintDamping );
  8088. SetPixelShaderConstantInternal( nReg, psReg.Base(), 1, false );
  8089. }
  8090. break;
  8091. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARCOLORSPACE:
  8092. {
  8093. // Skip the command.
  8094. pCmdBuf += sizeof( int );
  8095. // Read the register number that we want to write the colormodulation value into.
  8096. int nReg = GetData<int>( pCmdBuf );
  8097. pCmdBuf += sizeof( int ); // skip register
  8098. if ( config.nFullbright != 2 )
  8099. {
  8100. if ( USE_OLD_GAMMA )
  8101. {
  8102. // Read the material-level gamma color scale ($color2)
  8103. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  8104. // Get the per-model-instance diffuse modulation
  8105. const Vector4D &srcColor = instance.m_DiffuseModulation;
  8106. Vector4D color;
  8107. color[0] = srcColor[0] * vSrcColor2[0];
  8108. color[1] = srcColor[1] * vSrcColor2[1];
  8109. color[2] = srcColor[2] * vSrcColor2[2];
  8110. color[3] = srcColor[3];
  8111. color[0] = color[0] > 1.0f ? color[0] : GammaToLinear( color[0] );
  8112. color[1] = color[1] > 1.0f ? color[1] : GammaToLinear( color[1] );
  8113. color[2] = color[2] > 1.0f ? color[2] : GammaToLinear( color[2] );
  8114. SetPixelShaderConstantInternal( nReg, color.Base() );
  8115. }
  8116. else
  8117. {
  8118. // Read the material-level gamma color scale ($color2)
  8119. fltx4 fl4DiffuseModulation = LoadUnalignedSIMD( &instance.m_DiffuseModulation );
  8120. fltx4 fl4Color = GammaToLinearExtendedSIMD( MulSIMD( LoadUnalignedSIMD( pCmdBuf ),fl4DiffuseModulation ) );
  8121. // restore alpha
  8122. fl4Color = SetWSIMD( fl4Color, fl4DiffuseModulation );
  8123. SetPixelShaderConstantInternal( nReg, (float const * ) &fl4Color );
  8124. }
  8125. }
  8126. else
  8127. {
  8128. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  8129. SetPixelShaderConstantInternal( nReg, white.Base() );
  8130. }
  8131. pCmdBuf += sizeof( Vector4D ); // skip vSrcColor2 Vector
  8132. }
  8133. break;
  8134. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE:
  8135. {
  8136. // Skip the command.
  8137. pCmdBuf += sizeof( int );
  8138. // Read the register number that we want to write the colormodulation value into.
  8139. int nReg = GetData<int>( pCmdBuf );
  8140. pCmdBuf += sizeof( int ); // skip register
  8141. // Read the material-level gamma color scale ($color2)
  8142. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  8143. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  8144. if ( config.nFullbright != 2 )
  8145. {
  8146. // Get the per-model-instance diffuse modulation
  8147. const Vector4D &srcColor = instance.m_DiffuseModulation;
  8148. Vector4D color;
  8149. color[0] = srcColor[0] * vSrcColor2[0];
  8150. color[1] = srcColor[1] * vSrcColor2[1];
  8151. color[2] = srcColor[2] * vSrcColor2[2];
  8152. color[3] = srcColor[3];
  8153. SetPixelShaderConstantInternal( nReg, color.Base() );
  8154. }
  8155. else
  8156. {
  8157. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  8158. SetPixelShaderConstantInternal( nReg, white.Base() );
  8159. }
  8160. }
  8161. break;
  8162. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_IDENTITY:
  8163. {
  8164. // Skip the command.
  8165. pCmdBuf += sizeof( int );
  8166. // Read the register number that we want to write the colormodulation value into.
  8167. int nReg = GetData<int>( pCmdBuf );
  8168. pCmdBuf += sizeof( int ); // skip register
  8169. Vector4D color( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  8170. SetPixelShaderConstantInternal( nReg, color.Base() );
  8171. }
  8172. break;
  8173. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARCOLORSPACE_LINEARSCALE:
  8174. {
  8175. // Skip the command.
  8176. pCmdBuf += sizeof( int );
  8177. // Read the register number that we want to write the colormodulation value into.
  8178. int nReg = GetData<int>( pCmdBuf );
  8179. pCmdBuf += sizeof( int ); // skip register
  8180. if ( config.nFullbright != 2 )
  8181. {
  8182. // Read the material-level gamma color scale ($color2)
  8183. if ( USE_OLD_GAMMA )
  8184. {
  8185. Vector4D vSrcColor2 = GetData<Vector4D>( pCmdBuf );
  8186. pCmdBuf += sizeof( Vector4D ); // skip vSrcColor2 Vector
  8187. // Read the linear scale value
  8188. float scale = GetData<float>( pCmdBuf );
  8189. pCmdBuf += sizeof( float ); // skip the linear scale value
  8190. // Get the per-model-instance diffuse modulation
  8191. const Vector4D &srcColor = instance.m_DiffuseModulation;
  8192. Vector4D color;
  8193. color[0] = srcColor[0] * vSrcColor2[0];
  8194. color[1] = srcColor[1] * vSrcColor2[1];
  8195. color[2] = srcColor[2] * vSrcColor2[2];
  8196. color[3] = srcColor[3];
  8197. color[0] = ( color[0] > 1.0f ? color[0] : GammaToLinear( color[0] ) ) * scale;
  8198. color[1] = ( color[1] > 1.0f ? color[1] : GammaToLinear( color[1] ) ) * scale;
  8199. color[2] = ( color[2] > 1.0f ? color[2] : GammaToLinear( color[2] ) ) * scale;
  8200. SetPixelShaderConstantInternal( nReg, color.Base() );
  8201. }
  8202. else
  8203. {
  8204. fltx4 fl4SrcColor2 = LoadUnaligned3SIMD( pCmdBuf );
  8205. pCmdBuf += sizeof( Vector4D );
  8206. float scale = GetData<float>( pCmdBuf );
  8207. pCmdBuf += sizeof( float ); // skip the linear scale value
  8208. fltx4 fl4Scale = ReplicateX4( scale );
  8209. fltx4 fl4SrcColor = LoadUnalignedSIMD( &instance.m_DiffuseModulation );
  8210. fl4SrcColor2 = MulSIMD( GammaToLinearExtendedSIMD( MulSIMD( fl4SrcColor2, fl4SrcColor ) ), fl4Scale );
  8211. fl4SrcColor2 = SetWSIMD( fl4SrcColor2, fl4SrcColor ); // copy back the original unmodified alpha
  8212. SetPixelShaderConstantInternal( nReg, ( float const * ) &fl4SrcColor2 );
  8213. }
  8214. }
  8215. else
  8216. {
  8217. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  8218. SetPixelShaderConstantInternal( nReg, white.Base() );
  8219. pCmdBuf += sizeof( float ) + sizeof( Vector4D );
  8220. }
  8221. }
  8222. break;
  8223. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARSCALE:
  8224. {
  8225. // Skip the command.
  8226. pCmdBuf += sizeof( int );
  8227. // Read the register number that we want to write the colormodulation value into.
  8228. int nReg = GetData<int>( pCmdBuf );
  8229. pCmdBuf += sizeof( int ); // skip register
  8230. // Read the material-level gamma color scale ($color2)
  8231. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  8232. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  8233. // skip the pad
  8234. pCmdBuf += sizeof( float );
  8235. // Read the linear scale value
  8236. float scale = GetData<float>( pCmdBuf );
  8237. pCmdBuf += sizeof( float ); // skip the linear scale value
  8238. if (config.nFullbright != 2 )
  8239. {
  8240. // Get the per-model-instance diffuse modulation
  8241. const Vector4D &srcColor = instance.m_DiffuseModulation;
  8242. Vector4D color;
  8243. color[0] = srcColor[0] * vSrcColor2[0] * scale;
  8244. color[1] = srcColor[1] * vSrcColor2[1] * scale;
  8245. color[2] = srcColor[2] * vSrcColor2[2] * scale;
  8246. color[3] = srcColor[3];
  8247. SetPixelShaderConstantInternal( nReg, color.Base() );
  8248. }
  8249. else
  8250. {
  8251. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  8252. SetPixelShaderConstantInternal( nReg, white.Base() );
  8253. }
  8254. }
  8255. break;
  8256. case CBICMD_SETMODULATIONPIXELSHADERDYNAMICSTATE_LINEARSCALE_SCALEINW:
  8257. {
  8258. // Skip the command.
  8259. pCmdBuf += sizeof( int );
  8260. // Read the register number that we want to write the colormodulation value into.
  8261. int nReg = GetData<int>( pCmdBuf );
  8262. pCmdBuf += sizeof( int ); // skip register
  8263. // Read the material-level gamma color scale ($color2)
  8264. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  8265. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  8266. // Read the linear scale value
  8267. float scale = GetData<float>( pCmdBuf );
  8268. pCmdBuf += sizeof( float ); // skip the linear scale value
  8269. if ( config.nFullbright != 2 )
  8270. {
  8271. // Get the per-model-instance diffuse modulation
  8272. const Vector4D &srcColor = instance.m_DiffuseModulation;
  8273. Vector4D color;
  8274. color[0] = srcColor[0] * vSrcColor2[0] * scale;
  8275. color[1] = srcColor[1] * vSrcColor2[1] * scale;
  8276. color[2] = srcColor[2] * vSrcColor2[2] * scale;
  8277. color[3] = scale;
  8278. SetPixelShaderConstantInternal( nReg, color.Base() );
  8279. }
  8280. else
  8281. {
  8282. Vector4D vecScale( scale, scale, scale, scale );
  8283. SetPixelShaderConstantInternal( nReg, vecScale.Base() );
  8284. }
  8285. }
  8286. break;
  8287. case CBICMD_SETMODULATIONVERTEXSHADERDYNAMICSTATE:
  8288. {
  8289. // Skip the command.
  8290. pCmdBuf += sizeof( int );
  8291. // Read the register number that we want to write the colormodulation value into.
  8292. int nReg = GetData<int>( pCmdBuf );
  8293. pCmdBuf += sizeof( int ); // skip register
  8294. // Read the material-level gamma color scale ($color2)
  8295. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  8296. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  8297. if ( config.nFullbright != 2 )
  8298. {
  8299. // Get the per-model-instance diffuse modulation
  8300. const Vector4D &srcColor = instance.m_DiffuseModulation;
  8301. Vector4D color;
  8302. color[0] = srcColor[0] * vSrcColor2[0];
  8303. color[1] = srcColor[1] * vSrcColor2[1];
  8304. color[2] = srcColor[2] * vSrcColor2[2];
  8305. color[3] = srcColor[3];
  8306. SetVertexShaderConstantInternal( nReg, color.Base() );
  8307. }
  8308. else
  8309. {
  8310. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  8311. SetVertexShaderConstantInternal( nReg, white.Base() );
  8312. }
  8313. }
  8314. break;
  8315. case CBICMD_SETMODULATIONVERTEXSHADERDYNAMICSTATE_LINEARSCALE:
  8316. {
  8317. // Skip the command.
  8318. pCmdBuf += sizeof( int );
  8319. // Read the register number that we want to write the colormodulation value into.
  8320. int nReg = GetData<int>( pCmdBuf );
  8321. pCmdBuf += sizeof( int ); // skip register
  8322. // Read the material-level gamma color scale ($color2)
  8323. Vector vSrcColor2 = GetData<Vector>( pCmdBuf );
  8324. pCmdBuf += sizeof( Vector ); // skip vSrcColor2 Vector
  8325. float flScale = GetData<float>( pCmdBuf );
  8326. pCmdBuf += sizeof( float );
  8327. if ( config.nFullbright != 2 )
  8328. {
  8329. // Get the per-model-instance diffuse modulation
  8330. const Vector4D &srcColor = instance.m_DiffuseModulation;
  8331. Vector4D color;
  8332. color[0] = srcColor[0] * vSrcColor2[0] * flScale;
  8333. color[1] = srcColor[1] * vSrcColor2[1] * flScale;
  8334. color[2] = srcColor[2] * vSrcColor2[2] * flScale;
  8335. color[3] = srcColor[3];
  8336. SetVertexShaderConstantInternal( nReg, color.Base() );
  8337. }
  8338. else
  8339. {
  8340. Vector4D white( 1.0f, 1.0f, 1.0f, instance.m_DiffuseModulation[3] );
  8341. SetVertexShaderConstantInternal( nReg, white.Base() );
  8342. }
  8343. }
  8344. break;
  8345. #ifndef NDEBUG
  8346. default:
  8347. Warning( " unknown instance command %d last = %d\n", nCmd, GetData<int>( pLastCmd ) );
  8348. DebuggerBreak();
  8349. break;
  8350. #endif
  8351. }
  8352. pLastCmd = pCmd;
  8353. }
  8354. }
  8355. #endif //_PS3
  8356. //-----------------------------------------------------------------------------
  8357. // Sets state on the board related to the texture state
  8358. //-----------------------------------------------------------------------------
  8359. #ifndef _PS3
  8360. void CShaderAPIDx8::SetTextureState( Sampler_t sampler, TextureBindFlags_t nBindFlags, ShaderAPITextureHandle_t hTexture, bool force )
  8361. {
  8362. // Get the dynamic texture info
  8363. SamplerState_t &samplerState = SamplerState( sampler );
  8364. // Set the texture state, but only if it changes
  8365. if ( ( samplerState.m_BoundTexture == hTexture ) && ( LastSetTextureBindFlags( sampler ) == nBindFlags ) && !force )
  8366. return;
  8367. // Disabling texturing
  8368. if ( hTexture == INVALID_SHADERAPI_TEXTURE_HANDLE || WouldBeOverTextureLimit( hTexture ) )
  8369. {
  8370. Dx9Device()->SetTexture( sampler, 0 );
  8371. return;
  8372. }
  8373. samplerState.m_BoundTexture = hTexture;
  8374. RECORD_COMMAND( DX8_SET_TEXTURE, 3 );
  8375. RECORD_INT( sampler );
  8376. RECORD_INT( hTexture );
  8377. RECORD_INT( GetTexture( hTexture).m_CurrentCopy );
  8378. IDirect3DBaseTexture *pTexture = CShaderAPIDx8::GetD3DTexture( hTexture );
  8379. #if defined( _X360 )
  8380. GPUTEXTURE_FETCH_CONSTANT linearFormatBackup = pTexture->Format;
  8381. if ( nBindFlags & TEXTURE_BINDFLAGS_SRGBREAD )
  8382. {
  8383. #if defined( CSTRIKE15 )
  8384. // [mariod] - no PWL textures
  8385. // TODO - ensure all textures coming through here are set appropriately for shader srgb reads (not all shaders currently set to do this)
  8386. #else
  8387. // Use X360 HW path
  8388. if ( r_use16bit_srgb_sampling.GetBool() )
  8389. {
  8390. // Convert the GPU format to an EXPAND or AS_16 higher precision variant if one is available, and enable GAMMA.
  8391. ConvertTextureToAs16SRGBFormat( reinterpret_cast< D3DTexture * >( pTexture ) );
  8392. }
  8393. else
  8394. {
  8395. // convert to srgb format for the bind. This effectively emulates the old srgb read sampler state
  8396. pTexture->Format.SignX = pTexture->Format.SignY = pTexture->Format.SignZ = 3;
  8397. }
  8398. #endif
  8399. }
  8400. #else
  8401. SetSamplerState( sampler, D3DSAMP_SRGBTEXTURE, ( nBindFlags & TEXTURE_BINDFLAGS_SRGBREAD ) != 0 );
  8402. #endif
  8403. samplerState.m_nTextureBindFlags = nBindFlags;
  8404. TouchTexture( sampler, pTexture );
  8405. Dx9Device()->SetTexture( sampler, pTexture );
  8406. #if defined( _X360 )
  8407. // put the format back in linear space
  8408. pTexture->Format = linearFormatBackup;
  8409. #endif
  8410. Texture_t &tex = GetTexture( hTexture );
  8411. if ( tex.m_LastBoundFrame != m_CurrentFrame )
  8412. {
  8413. tex.m_LastBoundFrame = m_CurrentFrame;
  8414. tex.m_nTimesBoundThisFrame = 0;
  8415. if ( tex.m_pTextureGroupCounterFrame )
  8416. {
  8417. // Update the per-frame texture group counter.
  8418. *tex.m_pTextureGroupCounterFrame += tex.GetMemUsage();
  8419. }
  8420. // Track memory usage.
  8421. m_nTextureMemoryUsedLastFrame += tex.GetMemUsage();
  8422. }
  8423. if ( !m_bDebugTexturesRendering )
  8424. ++tex.m_nTimesBoundThisFrame;
  8425. tex.m_nTimesBoundMax = MAX( tex.m_nTimesBoundMax, tex.m_nTimesBoundThisFrame );
  8426. MaterialSystem_Config_t &config = ShaderUtil()->GetConfig();
  8427. bool noFilter = config.bFilterTextures == 0;
  8428. bool noMipFilter = config.bMipMapTextures == 0;
  8429. // Set SHADOWFILTER or ATI Fetch4
  8430. #if defined ( DX_TO_GL_ABSTRACTION ) && !defined( _PS3 )
  8431. const uint nNewShadowFilterState = ( nBindFlags & TEXTURE_BINDFLAGS_SHADOWDEPTH ) ? 1 : 0;
  8432. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_SHADOWFILTER, m_bShadowFilterEnable, nNewShadowFilterState );
  8433. #elif !defined( PLATFORM_X360 )
  8434. if ( g_pHardwareConfig->SupportsFetch4() )
  8435. {
  8436. const uint nNewFetch4State = ( nBindFlags & TEXTURE_BINDFLAGS_SHADOWDEPTH ) ? ATI_FETCH4_ENABLE : ATI_FETCH4_DISABLE;
  8437. SETSAMPLESTATEANDMIRROR( sampler, samplerState, ATISAMP_FETCH4, m_bShadowFilterEnable, nNewFetch4State );
  8438. if ( nBindFlags & TEXTURE_BINDFLAGS_SHADOWDEPTH )
  8439. {
  8440. noFilter = true;
  8441. noMipFilter = true;
  8442. }
  8443. }
  8444. #endif
  8445. if ( nBindFlags & TEXTURE_BINDFLAGS_NOMIP )
  8446. {
  8447. noMipFilter = true;
  8448. }
  8449. D3DTEXTUREFILTERTYPE minFilter = noFilter ? D3DTEXF_NONE : D3DTEXTUREFILTERTYPE(tex.m_MinFilter);
  8450. D3DTEXTUREFILTERTYPE magFilter = noFilter ? D3DTEXF_NONE : D3DTEXTUREFILTERTYPE(tex.m_MagFilter);
  8451. D3DTEXTUREFILTERTYPE mipFilter = D3DTEXTUREFILTERTYPE(tex.m_MipFilter);
  8452. if ( noMipFilter )
  8453. {
  8454. mipFilter = D3DTEXF_NONE;
  8455. }
  8456. else if ( noFilter )
  8457. {
  8458. mipFilter = D3DTEXF_POINT;
  8459. }
  8460. D3DTEXTUREADDRESS uTexWrap = D3DTEXTUREADDRESS(tex.m_UTexWrap);
  8461. D3DTEXTUREADDRESS vTexWrap = D3DTEXTUREADDRESS(tex.m_VTexWrap);
  8462. D3DTEXTUREADDRESS wTexWrap = D3DTEXTUREADDRESS(tex.m_WTexWrap);
  8463. #if DX_TO_GL_ABSTRACTION
  8464. if ( ( samplerState.m_MinFilter != minFilter ) || ( samplerState.m_MagFilter != magFilter ) || ( samplerState.m_MipFilter != mipFilter ) ||
  8465. ( samplerState.m_UTexWrap != uTexWrap ) || ( samplerState.m_VTexWrap != vTexWrap ) || ( samplerState.m_WTexWrap != wTexWrap ) )
  8466. {
  8467. samplerState.m_UTexWrap = uTexWrap;
  8468. samplerState.m_VTexWrap = vTexWrap;
  8469. samplerState.m_WTexWrap = wTexWrap;
  8470. samplerState.m_MinFilter = minFilter;
  8471. samplerState.m_MagFilter = magFilter;
  8472. samplerState.m_MipFilter = mipFilter;
  8473. Dx9Device()->SetSamplerStates( sampler, uTexWrap, vTexWrap, wTexWrap, minFilter, magFilter, mipFilter );
  8474. }
  8475. #else
  8476. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSU, m_UTexWrap, uTexWrap );
  8477. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSV, m_VTexWrap, vTexWrap );
  8478. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSW, m_WTexWrap, wTexWrap );
  8479. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MINFILTER, m_MinFilter, minFilter );
  8480. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MAGFILTER, m_MagFilter, magFilter );
  8481. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MIPFILTER, m_MipFilter, mipFilter );
  8482. #endif
  8483. }
  8484. void CShaderAPIDx8::SetTextureFilterMode( Sampler_t sampler, TextureFilterMode_t nMode )
  8485. {
  8486. SamplerState_t &samplerState = SamplerState( sampler );
  8487. D3DTEXTUREFILTERTYPE minFilter = samplerState.m_MinFilter;
  8488. D3DTEXTUREFILTERTYPE magFilter = samplerState.m_MagFilter;
  8489. D3DTEXTUREFILTERTYPE mipFilter = samplerState.m_MipFilter;
  8490. switch( nMode )
  8491. {
  8492. case TFILTER_MODE_POINTSAMPLED:
  8493. minFilter = D3DTEXF_POINT;
  8494. magFilter = D3DTEXF_POINT;
  8495. mipFilter = D3DTEXF_POINT;
  8496. break;
  8497. }
  8498. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MINFILTER, m_MinFilter, minFilter );
  8499. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MAGFILTER, m_MagFilter, magFilter );
  8500. SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MIPFILTER, m_MipFilter, mipFilter );
  8501. }
  8502. void CShaderAPIDx8::BindTexture( Sampler_t sampler, TextureBindFlags_t nBindFlags, ShaderAPITextureHandle_t textureHandle )
  8503. {
  8504. LOCK_SHADERAPI();
  8505. // A little trickery to deal with instance-based rendering.
  8506. // BindTexture calls are expected to come from shaders. We need to sniff the
  8507. // state sets here to see if any bind are set to the current local env cubemap.
  8508. // If so, we need to keep track of that so that when we change per-instance
  8509. // state, we know that we need to change these textures. Each time we start
  8510. // rendering a new pass, we reset the bitfield indicating which samplers to modify.
  8511. if ( IsRenderingInstances() )
  8512. {
  8513. int nMask = ( 1 << sampler );
  8514. m_DynamicState.m_nLocalEnvCubemapSamplers &= ~nMask;
  8515. m_DynamicState.m_nLightmapSamplers &= ~nMask;
  8516. m_DynamicState.m_nPaintmapSamplers &= ~nMask;
  8517. bool bIsLocalEnvCubemap = ( textureHandle == m_StdTextureHandles[TEXTURE_LOCAL_ENV_CUBEMAP] );
  8518. if ( bIsLocalEnvCubemap )
  8519. {
  8520. m_DynamicState.m_nLocalEnvCubemapSamplers |= nMask;
  8521. SetLastSetTextureBindFlags( sampler, nBindFlags );
  8522. return;
  8523. }
  8524. bool bIsLightmap = ( textureHandle == m_StdTextureHandles[TEXTURE_LIGHTMAP] );
  8525. if ( bIsLightmap )
  8526. {
  8527. m_DynamicState.m_nLightmapSamplers |= nMask;
  8528. SetLastSetTextureBindFlags( sampler, nBindFlags );
  8529. return;
  8530. }
  8531. bool bIsPaintmap = ( textureHandle == m_StdTextureHandles[TEXTURE_PAINT] );
  8532. if ( bIsPaintmap )
  8533. {
  8534. m_DynamicState.m_nPaintmapSamplers |= nMask;
  8535. SetLastSetTextureBindFlags( sampler, nBindFlags );
  8536. return;
  8537. }
  8538. }
  8539. SetTextureState( sampler, nBindFlags, textureHandle );
  8540. }
  8541. #endif
  8542. void CShaderAPIDx8::BindVertexTexture( VertexTextureSampler_t nStage, ShaderAPITextureHandle_t textureHandle )
  8543. {
  8544. Assert( g_pMaterialSystemHardwareConfig->GetVertexSamplerCount() != 0 );
  8545. LOCK_SHADERAPI();
  8546. ADD_VERTEX_TEXTURE_FUNC( COMMIT_PER_PASS, CommitVertexTextures, nStage, m_BoundVertexTexture, textureHandle );
  8547. }
  8548. //-----------------------------------------------------------------------------
  8549. // Texture allocation/deallocation
  8550. //-----------------------------------------------------------------------------
  8551. //-----------------------------------------------------------------------------
  8552. // Computes stats info for a texture
  8553. //-----------------------------------------------------------------------------
  8554. void CShaderAPIDx8::ComputeStatsInfo( ShaderAPITextureHandle_t hTexture, bool bIsCubeMap, bool isVolumeTexture )
  8555. {
  8556. Texture_t &textureData = GetTexture( hTexture );
  8557. textureData.m_SizeBytes = 0;
  8558. textureData.m_SizeTexels = 0;
  8559. textureData.m_LastBoundFrame = -1;
  8560. if ( IsX360() )
  8561. {
  8562. textureData.m_nTimesBoundThisFrame = 0;
  8563. }
  8564. IDirect3DBaseTexture* pD3DTex = CShaderAPIDx8::GetD3DTexture( hTexture );
  8565. if ( IsPC() || !IsX360() )
  8566. {
  8567. if ( bIsCubeMap )
  8568. {
  8569. IDirect3DCubeTexture* pTex = static_cast<IDirect3DCubeTexture*>(pD3DTex);
  8570. if ( !pTex )
  8571. {
  8572. Assert( 0 );
  8573. return;
  8574. }
  8575. int numLevels = pTex->GetLevelCount();
  8576. for (int i = 0; i < numLevels; ++i)
  8577. {
  8578. D3DSURFACE_DESC desc;
  8579. HRESULT hr = pTex->GetLevelDesc( i, &desc );
  8580. Assert( !FAILED(hr) );
  8581. textureData.m_SizeBytes += 6 * ImageLoader::GetMemRequired( desc.Width, desc.Height, 1, textureData.GetImageFormat(), false );
  8582. textureData.m_SizeTexels += 6 * desc.Width * desc.Height;
  8583. }
  8584. }
  8585. else if ( isVolumeTexture )
  8586. {
  8587. IDirect3DVolumeTexture9* pTex = static_cast<IDirect3DVolumeTexture9*>(pD3DTex);
  8588. if ( !pTex )
  8589. {
  8590. Assert( 0 );
  8591. return;
  8592. }
  8593. int numLevels = pTex->GetLevelCount();
  8594. for (int i = 0; i < numLevels; ++i)
  8595. {
  8596. D3DVOLUME_DESC desc;
  8597. HRESULT hr = pTex->GetLevelDesc( i, &desc );
  8598. Assert( !FAILED( hr ) );
  8599. textureData.m_SizeBytes += ImageLoader::GetMemRequired( desc.Width, desc.Height, desc.Depth, textureData.GetImageFormat(), false );
  8600. textureData.m_SizeTexels += desc.Width * desc.Height;
  8601. }
  8602. }
  8603. else
  8604. {
  8605. IDirect3DTexture* pTex = static_cast<IDirect3DTexture*>(pD3DTex);
  8606. if ( !pTex )
  8607. {
  8608. Assert( 0 );
  8609. return;
  8610. }
  8611. int numLevels = pTex->GetLevelCount();
  8612. for (int i = 0; i < numLevels; ++i)
  8613. {
  8614. D3DSURFACE_DESC desc;
  8615. HRESULT hr = pTex->GetLevelDesc( i, &desc );
  8616. Assert( !FAILED( hr ) );
  8617. textureData.m_SizeBytes += ImageLoader::GetMemRequired( desc.Width, desc.Height, 1, textureData.GetImageFormat(), false );
  8618. textureData.m_SizeTexels += desc.Width * desc.Height;
  8619. }
  8620. }
  8621. }
  8622. #if defined( _X360 )
  8623. // 360 uses gpu storage size (which accounts for page alignment bloat), not format size
  8624. textureData.m_SizeBytes = g_TextureHeap.GetSize( pD3DTex );
  8625. #endif
  8626. }
  8627. static D3DFORMAT ComputeFormat( IDirect3DBaseTexture* pTexture, bool bIsCubeMap )
  8628. {
  8629. Assert( pTexture );
  8630. D3DSURFACE_DESC desc;
  8631. if ( bIsCubeMap )
  8632. {
  8633. IDirect3DCubeTexture* pTex = static_cast<IDirect3DCubeTexture*>(pTexture);
  8634. HRESULT hr = pTex->GetLevelDesc( 0, &desc );
  8635. Assert( !FAILED(hr) );
  8636. }
  8637. else
  8638. {
  8639. IDirect3DTexture* pTex = static_cast<IDirect3DTexture*>(pTexture);
  8640. HRESULT hr = pTex->GetLevelDesc( 0, &desc );
  8641. Assert( !FAILED(hr) );
  8642. }
  8643. return desc.Format;
  8644. }
  8645. ShaderAPITextureHandle_t CShaderAPIDx8::CreateDepthTexture(
  8646. ImageFormat renderTargetFormat,
  8647. int width,
  8648. int height,
  8649. const char *pDebugName,
  8650. bool bTexture,
  8651. bool bAliasDepthSurfaceOverColorX360 )
  8652. {
  8653. bAliasDepthSurfaceOverColorX360;
  8654. LOCK_SHADERAPI();
  8655. ShaderAPITextureHandle_t i = CreateTextureHandle();
  8656. Texture_t *pTexture = &GetTexture( i );
  8657. pTexture->m_Flags = Texture_t::IS_ALLOCATED;
  8658. if( bTexture )
  8659. {
  8660. pTexture->m_Flags |= Texture_t::IS_DEPTH_STENCIL_TEXTURE;
  8661. }
  8662. else
  8663. {
  8664. pTexture->m_Flags |= Texture_t::IS_DEPTH_STENCIL;
  8665. }
  8666. pTexture->m_DebugName = pDebugName;
  8667. pTexture->m_Width = width;
  8668. pTexture->m_Height = height;
  8669. pTexture->m_Depth = 1; // fake
  8670. pTexture->m_Count = 1; // created single texture
  8671. pTexture->m_CountIndex = 0; // created single texture
  8672. pTexture->m_CreationFlags = 0; // fake
  8673. pTexture->m_NumCopies = 1;
  8674. pTexture->m_CurrentCopy = 0;
  8675. ImageFormat renderFormat = ImageLoader::D3DFormatToImageFormat( FindNearestSupportedFormat( renderTargetFormat, false, true, false ) );
  8676. #if defined( _X360 )
  8677. D3DFORMAT nDepthFormat = ReverseDepthOnX360() ? D3DFMT_D24FS8 : D3DFMT_D24S8;
  8678. #else
  8679. D3DFORMAT nDepthFormat = m_bUsingStencil ? D3DFMT_D24S8 : D3DFMT_D24X8;
  8680. #endif
  8681. D3DFORMAT format = FindNearestSupportedDepthFormat( m_nAdapter, m_AdapterFormat, renderFormat, nDepthFormat );
  8682. D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_NONE;
  8683. pTexture->m_NumLevels = 1;
  8684. pTexture->m_SizeTexels = width * height;
  8685. pTexture->m_SizeBytes = ImageLoader::GetMemRequired( width, height, 1, renderFormat, false );
  8686. RECORD_COMMAND( DX8_CREATE_DEPTH_TEXTURE, 5 );
  8687. RECORD_INT( i );
  8688. RECORD_INT( width );
  8689. RECORD_INT( height );
  8690. RECORD_INT( format );
  8691. RECORD_INT( multisampleType );
  8692. HRESULT hr;
  8693. if ( !bTexture )
  8694. {
  8695. #if defined( _X360 )
  8696. int backWidth, backHeight;
  8697. ShaderAPI()->GetBackBufferDimensions( backWidth, backHeight );
  8698. D3DFORMAT backBufferFormat = ImageLoader::ImageFormatToD3DFormat( g_pShaderDevice->GetBackBufferFormat() );
  8699. // immediately follows back buffer in EDRAM
  8700. D3DSURFACE_PARAMETERS surfParameters;
  8701. V_memset( &surfParameters, 0, sizeof( surfParameters ) );
  8702. // FIXME: The multiply by two below seems suspect. I believe it's to account for size of the color buffer AND the size of the
  8703. // depth buffer, but it assumes that both buffers always have the same size. This is probably the case now, but might not be in the future.
  8704. surfParameters.Base = 2*XGSurfaceSize( backWidth, backHeight, backBufferFormat, g_TextureHeap.GetBackBufferMultiSampleType() );
  8705. if ( !bAliasDepthSurfaceOverColorX360 )
  8706. {
  8707. // If we don't do this, the color RT and depth RT will be co-located in EDRAM
  8708. surfParameters.Base += XGSurfaceSize( width, height, ImageLoader::ImageFormatToD3DFormat( renderFormat ), D3DMULTISAMPLE_NONE );
  8709. }
  8710. surfParameters.ColorExpBias = 0;
  8711. surfParameters.HierarchicalZBase = 0;
  8712. surfParameters.HiZFunc = D3DHIZFUNC_DEFAULT;
  8713. if ( XGHierarchicalZSize( backWidth, backHeight, D3DMULTISAMPLE_NONE ) + XGHierarchicalZSize( width, height, D3DMULTISAMPLE_NONE ) > GPU_HIERARCHICAL_Z_TILES )
  8714. {
  8715. // overflow, disable HiZ
  8716. surfParameters.HierarchicalZBase = 0xFFFFFFFF;
  8717. }
  8718. hr = Dx9Device()->CreateDepthStencilSurface(
  8719. width, height, format, multisampleType, 0, TRUE, &pTexture->GetDepthStencilSurface(), &surfParameters );
  8720. #else
  8721. hr = Dx9Device()->CreateDepthStencilSurface(
  8722. width, height, format, multisampleType, 0, TRUE, &pTexture->GetDepthStencilSurface(), NULL );
  8723. #endif
  8724. }
  8725. else
  8726. {
  8727. IDirect3DTexture9 *pTex;
  8728. hr = Dx9Device()->CreateTexture( width, height, 1, D3DUSAGE_DEPTHSTENCIL, format, D3DPOOL_DEFAULT, &pTex, NULL );
  8729. pTexture->SetTexture( pTex );
  8730. }
  8731. if ( FAILED( hr ) )
  8732. {
  8733. switch( hr )
  8734. {
  8735. case D3DERR_INVALIDCALL:
  8736. Warning( "ShaderAPIDX8::CreateDepthStencilSurface: D3DERR_INVALIDCALL\n" );
  8737. break;
  8738. case D3DERR_OUTOFVIDEOMEMORY:
  8739. Warning( "ShaderAPIDX8::CreateDepthStencilSurface: D3DERR_OUTOFVIDEOMEMORY\n" );
  8740. break;
  8741. default:
  8742. break;
  8743. }
  8744. Assert( 0 );
  8745. }
  8746. return i;
  8747. }
  8748. // FIXME!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  8749. // Could keep a free-list for this instead of linearly searching. We
  8750. // don't create textures all the time, so this is probably fine for now.
  8751. // FIXME!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  8752. ShaderAPITextureHandle_t CShaderAPIDx8::CreateTextureHandle( void )
  8753. {
  8754. ShaderAPITextureHandle_t handle = INVALID_SHADERAPI_TEXTURE_HANDLE;
  8755. CreateTextureHandles( &handle, 1, false );
  8756. return handle;
  8757. }
  8758. void CShaderAPIDx8::CreateTextureHandles( ShaderAPITextureHandle_t *pHandles, int nCount, bool bReuseHandles )
  8759. {
  8760. if ( nCount <= 0 )
  8761. return;
  8762. MEM_ALLOC_CREDIT();
  8763. ShaderAPITextureHandle_t hTexture;
  8764. if ( bReuseHandles )
  8765. {
  8766. int nValid = 0;
  8767. for ( int i = 0; i < nCount; i++ )
  8768. {
  8769. // prior handles were freed and caller wants them back
  8770. hTexture = pHandles[i];
  8771. if ( m_Textures.IsValidIndex( hTexture) && !( m_Textures[hTexture].m_Flags & Texture_t::IS_ALLOCATED ) )
  8772. {
  8773. nValid++;
  8774. }
  8775. }
  8776. if ( nValid == nCount )
  8777. {
  8778. // all prior handles are available and can be re-used
  8779. return;
  8780. }
  8781. }
  8782. int idxCreating = 0;
  8783. for ( hTexture = m_Textures.Head(); hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
  8784. {
  8785. if ( !( m_Textures[hTexture].m_Flags & Texture_t::IS_ALLOCATED ) )
  8786. {
  8787. pHandles[ idxCreating++ ] = hTexture;
  8788. if ( idxCreating >= nCount )
  8789. return;
  8790. }
  8791. }
  8792. while ( idxCreating < nCount )
  8793. {
  8794. pHandles[ idxCreating++ ] = m_Textures.AddToTail();
  8795. }
  8796. }
  8797. //-----------------------------------------------------------------------------
  8798. // Creates a lovely texture
  8799. //-----------------------------------------------------------------------------
  8800. ShaderAPITextureHandle_t CShaderAPIDx8::CreateTexture(
  8801. int width,
  8802. int height,
  8803. int depth,
  8804. ImageFormat dstImageFormat,
  8805. int numMipLevels,
  8806. int numCopies,
  8807. int creationFlags,
  8808. const char *pDebugName,
  8809. const char *pTextureGroupName )
  8810. {
  8811. ShaderAPITextureHandle_t handle = 0;
  8812. CreateTextures( &handle, 1, width, height, depth, dstImageFormat, numMipLevels, numCopies, creationFlags, pDebugName, pTextureGroupName );
  8813. return handle;
  8814. }
  8815. void CShaderAPIDx8::CreateTextures(
  8816. ShaderAPITextureHandle_t *pHandles,
  8817. int count,
  8818. int width,
  8819. int height,
  8820. int depth,
  8821. ImageFormat dstImageFormat,
  8822. int numMipLevels,
  8823. int numCopies,
  8824. int creationFlags,
  8825. const char *pDebugName,
  8826. const char *pTextureGroupName )
  8827. {
  8828. LOCK_SHADERAPI();
  8829. if ( depth == 0 )
  8830. {
  8831. depth = 1;
  8832. }
  8833. bool bIsCubeMap = ( creationFlags & TEXTURE_CREATE_CUBEMAP ) != 0;
  8834. bool bIsRenderTarget = ( creationFlags & TEXTURE_CREATE_RENDERTARGET ) != 0;
  8835. bool bIsManaged = ( creationFlags & TEXTURE_CREATE_MANAGED ) != 0;
  8836. bool bIsDepthBuffer = ( creationFlags & TEXTURE_CREATE_DEPTHBUFFER ) != 0;
  8837. bool bIsDynamic = ( creationFlags & TEXTURE_CREATE_DYNAMIC ) != 0;
  8838. bool isSRGB = ( creationFlags & TEXTURE_CREATE_SRGB ) != 0; // for Posix/GL only... not used here ?
  8839. bool bReuseHandles = ( creationFlags & TEXTURE_CREATE_REUSEHANDLES ) != 0;
  8840. // Can't be both managed + dynamic. Dynamic is an optimization, but
  8841. // if it's not managed, then we gotta do special client-specific stuff
  8842. // So, managed wins out!
  8843. if ( bIsManaged )
  8844. {
  8845. bIsDynamic = false;
  8846. }
  8847. // Create a set of texture handles
  8848. CreateTextureHandles( pHandles, count, bReuseHandles );
  8849. Texture_t **arrTxp = ( Texture_t ** ) stackalloc( count * sizeof( Texture_t * ) );
  8850. unsigned short usSetFlags = 0;
  8851. usSetFlags |= ( creationFlags & TEXTURE_CREATE_VERTEXTEXTURE) ? Texture_t::IS_VERTEX_TEXTURE : 0;
  8852. #if defined( _GAMECONSOLE )
  8853. usSetFlags |= ( creationFlags & TEXTURE_CREATE_RENDERTARGET ) ? Texture_t::IS_RENDER_TARGET : 0;
  8854. usSetFlags |= ( creationFlags & TEXTURE_CREATE_CANCONVERTFORMAT ) ? Texture_t::CAN_CONVERT_FORMAT : 0;
  8855. usSetFlags |= ( creationFlags & TEXTURE_CREATE_PWLCORRECTED ) ? Texture_t::IS_PWL_CORRECTED : 0;
  8856. usSetFlags |= ( creationFlags & TEXTURE_CREATE_ERROR ) ? Texture_t::IS_ERROR_TEXTURE : 0;
  8857. #endif
  8858. for ( int idxFrame = 0; idxFrame < count; ++ idxFrame )
  8859. {
  8860. arrTxp[ idxFrame ] = &GetTexture( pHandles[ idxFrame ] );
  8861. Texture_t *pTexture = arrTxp[ idxFrame ];
  8862. pTexture->m_Flags = Texture_t::IS_ALLOCATED;
  8863. pTexture->m_DebugName = pDebugName;
  8864. pTexture->m_Width = width;
  8865. pTexture->m_Height = height;
  8866. pTexture->m_Depth = depth;
  8867. pTexture->m_Count = count;
  8868. pTexture->m_CountIndex = idxFrame;
  8869. pTexture->m_CreationFlags = creationFlags;
  8870. pTexture->m_Flags |= usSetFlags;
  8871. RECORD_COMMAND( DX8_CREATE_TEXTURE, 12 );
  8872. RECORD_INT( textureHandle );
  8873. RECORD_INT( width );
  8874. RECORD_INT( height );
  8875. RECORD_INT( depth ); // depth for volume textures
  8876. RECORD_INT( FindNearestSupportedFormat(dstImageFormat) );
  8877. RECORD_INT( numMipLevels );
  8878. RECORD_INT( bIsCubeMap );
  8879. RECORD_INT( numCopies <= 1 ? 1 : numCopies );
  8880. RECORD_INT( bIsRenderTarget ? 1 : 0 );
  8881. RECORD_INT( bIsManaged );
  8882. RECORD_INT( bIsDepthBuffer ? 1 : 0 );
  8883. RECORD_INT( bIsDynamic ? 1 : 0 );
  8884. IDirect3DBaseTexture* pD3DTex;
  8885. // Set the initial texture state
  8886. if ( numCopies <= 1 )
  8887. {
  8888. pTexture->m_NumCopies = 1;
  8889. pD3DTex = CreateD3DTexture( width, height, depth, dstImageFormat, numMipLevels, creationFlags, (char*)pDebugName );
  8890. pTexture->SetTexture( pD3DTex );
  8891. }
  8892. else
  8893. {
  8894. pTexture->m_NumCopies = numCopies;
  8895. {
  8896. // X360TEMP
  8897. // MEM_ALLOC_CREDIT();
  8898. pTexture->GetTextureArray() = new IDirect3DBaseTexture* [numCopies];
  8899. }
  8900. for (int k = 0; k < numCopies; ++k)
  8901. {
  8902. pD3DTex = CreateD3DTexture( width, height, depth, dstImageFormat, numMipLevels, creationFlags, (char*)pDebugName );
  8903. pTexture->SetTexture( k, pD3DTex );
  8904. }
  8905. }
  8906. pTexture->m_CurrentCopy = 0;
  8907. pD3DTex = CShaderAPIDx8::GetD3DTexture( pHandles[ idxFrame ] );
  8908. #if defined( _X360 )
  8909. if ( pD3DTex )
  8910. {
  8911. D3DSURFACE_DESC desc;
  8912. HRESULT hr;
  8913. if ( creationFlags & TEXTURE_CREATE_CUBEMAP )
  8914. {
  8915. hr = ((IDirect3DCubeTexture *)pD3DTex)->GetLevelDesc( 0, &desc );
  8916. }
  8917. else
  8918. {
  8919. hr = ((IDirect3DTexture *)pD3DTex)->GetLevelDesc( 0, &desc );
  8920. }
  8921. Assert( !FAILED( hr ) );
  8922. // for proper info get the actual format because the input format may have been redirected
  8923. dstImageFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
  8924. Assert( dstImageFormat != IMAGE_FORMAT_UNKNOWN );
  8925. // track linear or tiled
  8926. if ( !XGIsTiledFormat( desc.Format ) )
  8927. {
  8928. pTexture->m_Flags |= Texture_t::IS_LINEAR;
  8929. }
  8930. if ( creationFlags & TEXTURE_CREATE_CACHEABLE )
  8931. {
  8932. // actual caching ability was resolved by the texture heap
  8933. if ( g_TextureHeap.IsTextureCacheManaged( pD3DTex ) )
  8934. {
  8935. pTexture->m_Flags |= Texture_t::IS_CACHEABLE;
  8936. }
  8937. }
  8938. }
  8939. #endif
  8940. pTexture->SetImageFormat( dstImageFormat );
  8941. pTexture->m_UTexWrap = D3DTADDRESS_CLAMP;
  8942. pTexture->m_VTexWrap = D3DTADDRESS_CLAMP;
  8943. pTexture->m_WTexWrap = D3DTADDRESS_CLAMP;
  8944. if ( bIsRenderTarget )
  8945. {
  8946. #if !defined( _X360 ) && !defined( _PS3 )
  8947. if ( ( g_pHardwareConfig->Caps().m_VendorID == VENDORID_ATI ) &&
  8948. ( ( dstImageFormat == IMAGE_FORMAT_D16_SHADOW ) || ( dstImageFormat == IMAGE_FORMAT_D24X8_SHADOW ) ) )
  8949. {
  8950. pTexture->m_MinFilter = pTexture->m_MagFilter = D3DTEXF_POINT;
  8951. }
  8952. else
  8953. #endif
  8954. {
  8955. pTexture->m_MinFilter = pTexture->m_MagFilter = D3DTEXF_LINEAR;
  8956. }
  8957. pTexture->m_NumLevels = 1;
  8958. pTexture->m_MipFilter = D3DTEXF_NONE;
  8959. }
  8960. else
  8961. {
  8962. pTexture->m_NumLevels = pD3DTex ? pD3DTex->GetLevelCount() : 1;
  8963. pTexture->m_MipFilter = (pTexture->m_NumLevels != 1) ? D3DTEXF_LINEAR : D3DTEXF_NONE;
  8964. pTexture->m_MinFilter = pTexture->m_MagFilter = D3DTEXF_LINEAR;
  8965. }
  8966. pTexture->m_SwitchNeeded = false;
  8967. ComputeStatsInfo( pHandles[idxFrame], bIsCubeMap, (depth > 1) );
  8968. SetupTextureGroup( pHandles[idxFrame], pTextureGroupName );
  8969. }
  8970. }
  8971. void CShaderAPIDx8::SetupTextureGroup( ShaderAPITextureHandle_t hTexture, const char *pTextureGroupName )
  8972. {
  8973. Texture_t *pTexture = &GetTexture( hTexture );
  8974. Assert( !pTexture->m_pTextureGroupCounterGlobal );
  8975. // Setup the texture group stuff.
  8976. if ( pTextureGroupName && pTextureGroupName[0] != 0 )
  8977. {
  8978. pTexture->m_TextureGroupName = pTextureGroupName;
  8979. }
  8980. else
  8981. {
  8982. pTexture->m_TextureGroupName = TEXTURE_GROUP_UNACCOUNTED;
  8983. }
  8984. // 360 cannot vprof due to multicore loading until vprof is reentrant and these counters are real.
  8985. #if defined( VPROF_ENABLED ) && !defined( _X360 )
  8986. char counterName[256];
  8987. Q_snprintf( counterName, sizeof( counterName ), "TexGroup_global_%s", pTexture->m_TextureGroupName.String() );
  8988. pTexture->m_pTextureGroupCounterGlobal = g_VProfCurrentProfile.FindOrCreateCounter( counterName, COUNTER_GROUP_TEXTURE_GLOBAL );
  8989. Q_snprintf( counterName, sizeof( counterName ), "TexGroup_frame_%s", pTexture->m_TextureGroupName.String() );
  8990. pTexture->m_pTextureGroupCounterFrame = g_VProfCurrentProfile.FindOrCreateCounter( counterName, COUNTER_GROUP_TEXTURE_PER_FRAME );
  8991. #else
  8992. pTexture->m_pTextureGroupCounterGlobal = NULL;
  8993. pTexture->m_pTextureGroupCounterFrame = NULL;
  8994. #endif
  8995. if ( pTexture->m_pTextureGroupCounterGlobal )
  8996. {
  8997. *pTexture->m_pTextureGroupCounterGlobal += pTexture->GetMemUsage();
  8998. }
  8999. }
  9000. //-----------------------------------------------------------------------------
  9001. // Deletes a texture...
  9002. //-----------------------------------------------------------------------------
  9003. void CShaderAPIDx8::DeleteD3DTexture( ShaderAPITextureHandle_t hTexture )
  9004. {
  9005. int numDeallocated = 0;
  9006. Texture_t &texture = GetTexture( hTexture );
  9007. if ( texture.m_Flags & Texture_t::IS_DEPTH_STENCIL )
  9008. {
  9009. // garymcthack - need to make sure that playback knows how to deal with these.
  9010. RECORD_COMMAND( DX8_DESTROY_DEPTH_TEXTURE, 1 );
  9011. RECORD_INT( hTexture );
  9012. if ( texture.GetDepthStencilSurface() )
  9013. {
  9014. int nRetVal = texture.GetDepthStencilSurface()->Release();
  9015. Assert( nRetVal == 0 );
  9016. texture.GetDepthStencilSurface() = 0;
  9017. numDeallocated = 1;
  9018. }
  9019. else
  9020. {
  9021. // FIXME: we hit this on shutdown of HLMV on some machines
  9022. Assert( 0 );
  9023. }
  9024. }
  9025. else if ( texture.m_NumCopies == 1 )
  9026. {
  9027. if ( texture.GetTexture() )
  9028. {
  9029. RECORD_COMMAND( DX8_DESTROY_TEXTURE, 1 );
  9030. RECORD_INT( hTexture );
  9031. DestroyD3DTexture( texture.GetTexture() );
  9032. texture.SetTexture( 0 );
  9033. numDeallocated = 1;
  9034. }
  9035. }
  9036. else
  9037. {
  9038. if ( texture.GetTextureArray() )
  9039. {
  9040. RECORD_COMMAND( DX8_DESTROY_TEXTURE, 1 );
  9041. RECORD_INT( hTexture );
  9042. // Multiple copy texture
  9043. for (int j = 0; j < texture.m_NumCopies; ++j)
  9044. {
  9045. if (texture.GetTexture( j ))
  9046. {
  9047. DestroyD3DTexture( texture.GetTexture( j ) );
  9048. texture.SetTexture( j, 0 );
  9049. ++numDeallocated;
  9050. }
  9051. }
  9052. delete [] texture.GetTextureArray();
  9053. texture.GetTextureArray() = 0;
  9054. }
  9055. }
  9056. texture.m_NumCopies = 0;
  9057. // Remove this texture from its global texture group counter.
  9058. if ( texture.m_pTextureGroupCounterGlobal )
  9059. {
  9060. *texture.m_pTextureGroupCounterGlobal -= texture.GetMemUsage();
  9061. // <sergiy> this is an old assert that Mike Dussault added in 2002. It affects computation of free memory. Iestyn said it's better to keep the assert in to find out what's wrong with free memory computation.
  9062. Assert( *texture.m_pTextureGroupCounterGlobal >= 0 );
  9063. texture.m_pTextureGroupCounterGlobal = NULL;
  9064. }
  9065. // remove this texture from std textures
  9066. for( int i=0 ; i < ARRAYSIZE( m_StdTextureHandles ) ; i++ )
  9067. {
  9068. if ( m_StdTextureHandles[i] == hTexture )
  9069. {
  9070. m_StdTextureHandles[i] = INVALID_SHADERAPI_TEXTURE_HANDLE;
  9071. }
  9072. }
  9073. }
  9074. //-----------------------------------------------------------------------------
  9075. // Unbinds a texture from all texture stages
  9076. //-----------------------------------------------------------------------------
  9077. void CShaderAPIDx8::UnbindTexture( ShaderAPITextureHandle_t hTexture )
  9078. {
  9079. // Make sure no texture units are currently bound to it...
  9080. for ( int unit = 0; unit < g_pHardwareConfig->GetSamplerCount(); ++unit )
  9081. {
  9082. if ( hTexture == SamplerState( unit ).m_BoundTexture )
  9083. {
  9084. // Gotta set this here because INVALID_SHADERAPI_TEXTURE_HANDLE means don't actually
  9085. // set bound texture (it's used for disabling texturemapping)
  9086. SamplerState( unit ).m_BoundTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
  9087. SetTextureState( (Sampler_t)unit, TEXTURE_BINDFLAGS_NONE, INVALID_SHADERAPI_TEXTURE_HANDLE );
  9088. }
  9089. }
  9090. int nVertexSamplerCount = g_pHardwareConfig->GetVertexSamplerCount();
  9091. for ( int nSampler = 0; nSampler < nVertexSamplerCount; ++nSampler )
  9092. {
  9093. if ( hTexture == m_DynamicState.m_VertexTextureState[ nSampler ].m_BoundVertexTexture )
  9094. {
  9095. // Gotta set this here because INVALID_SHADERAPI_TEXTURE_HANDLE means don't actually
  9096. // set bound texture (it's used for disabling texture mapping)
  9097. BindVertexTexture( (VertexTextureSampler_t)nSampler, INVALID_SHADERAPI_TEXTURE_HANDLE );
  9098. }
  9099. }
  9100. }
  9101. //-----------------------------------------------------------------------------
  9102. // Deletes a texture...
  9103. //-----------------------------------------------------------------------------
  9104. void CShaderAPIDx8::DeleteTexture( ShaderAPITextureHandle_t textureHandle )
  9105. {
  9106. LOCK_SHADERAPI();
  9107. AssertValidTextureHandle( textureHandle );
  9108. if ( !TextureIsAllocated( textureHandle ) )
  9109. {
  9110. // already deallocated
  9111. return;
  9112. }
  9113. // Unbind it!
  9114. UnbindTexture( textureHandle );
  9115. // Delete it baby
  9116. DeleteD3DTexture( textureHandle );
  9117. // Now remove the texture from the list
  9118. // Mark as deallocated so that it can be reused.
  9119. GetTexture( textureHandle ).m_Flags = 0;
  9120. }
  9121. void CShaderAPIDx8::WriteTextureToFile( ShaderAPITextureHandle_t hTexture, const char *szFileName )
  9122. {
  9123. Texture_t *pTexInt = &GetTexture( hTexture );
  9124. //Assert( pTexInt->IsCubeMap() == false );
  9125. //Assert( pTexInt->IsVolumeTexture() == false );
  9126. IDirect3DTexture *pD3DTexture = (IDirect3DTexture *)pTexInt->GetTexture();
  9127. // Get the level of the texture we want to read from
  9128. IDirect3DSurface* pTextureLevel;
  9129. HRESULT hr = hr = pD3DTexture ->GetSurfaceLevel( 0, &pTextureLevel );
  9130. if ( FAILED( hr ) )
  9131. return;
  9132. D3DSURFACE_DESC surfaceDesc;
  9133. pD3DTexture->GetLevelDesc( 0, &surfaceDesc );
  9134. D3DLOCKED_RECT lockedRect;
  9135. //if( pTexInt->m_Flags & Texture_t::IS_RENDER_TARGET )
  9136. #if !defined( _GAMECONSOLE ) //TODO: X360+PS3 versions
  9137. {
  9138. //render targets can't be locked, luckily we can copy the surface to system memory and lock that.
  9139. IDirect3DSurface *pSystemSurface;
  9140. Assert( !IsX360() );
  9141. hr = Dx9Device()->CreateOffscreenPlainSurface( surfaceDesc.Width, surfaceDesc.Height, surfaceDesc.Format, D3DPOOL_SYSTEMMEM, &pSystemSurface, NULL );
  9142. Assert( SUCCEEDED( hr ) );
  9143. pSystemSurface->GetDesc( &surfaceDesc );
  9144. hr = Dx9Device()->GetRenderTargetData( pTextureLevel, pSystemSurface );
  9145. Assert( SUCCEEDED( hr ) );
  9146. //pretend this is the texture level we originally grabbed with GetSurfaceLevel() and continue on
  9147. pTextureLevel->Release();
  9148. pTextureLevel = pSystemSurface;
  9149. }
  9150. #endif
  9151. // lock the region
  9152. if ( FAILED( pTextureLevel->LockRect( &lockedRect, NULL, D3DLOCK_READONLY ) ) )
  9153. {
  9154. Assert( 0 );
  9155. pTextureLevel->Release();
  9156. return;
  9157. }
  9158. TGAWriter::WriteTGAFile( szFileName, surfaceDesc.Width, surfaceDesc.Height, pTexInt->GetImageFormat(), (const uint8 *)lockedRect.pBits, lockedRect.Pitch );
  9159. if ( FAILED( pTextureLevel->UnlockRect() ) )
  9160. {
  9161. Assert( 0 );
  9162. pTextureLevel->Release();
  9163. return;
  9164. }
  9165. pTextureLevel->Release();
  9166. }
  9167. //-----------------------------------------------------------------------------
  9168. // Releases all textures
  9169. //-----------------------------------------------------------------------------
  9170. void CShaderAPIDx8::ReleaseAllTextures()
  9171. {
  9172. ClearStdTextureHandles();
  9173. ShaderAPITextureHandle_t hTexture;
  9174. for ( hTexture = m_Textures.Head(); hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
  9175. {
  9176. if ( TextureIsAllocated( hTexture ) )
  9177. {
  9178. // Delete it baby
  9179. DeleteD3DTexture( hTexture );
  9180. }
  9181. }
  9182. // Make sure all texture units are pointing to nothing
  9183. for (int unit = 0; unit < g_pHardwareConfig->GetSamplerCount(); ++unit )
  9184. {
  9185. SamplerState( unit ).m_BoundTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
  9186. SetTextureState( (Sampler_t)unit, TEXTURE_BINDFLAGS_NONE, INVALID_SHADERAPI_TEXTURE_HANDLE );
  9187. }
  9188. }
  9189. void CShaderAPIDx8::DeleteAllTextures()
  9190. {
  9191. ReleaseAllTextures();
  9192. m_Textures.Purge();
  9193. }
  9194. bool CShaderAPIDx8::IsTexture( ShaderAPITextureHandle_t textureHandle )
  9195. {
  9196. LOCK_SHADERAPI();
  9197. if ( !TextureIsAllocated( textureHandle ) )
  9198. {
  9199. return false;
  9200. }
  9201. #if !defined( _X360 )
  9202. if ( GetTexture( textureHandle ).m_Flags & Texture_t::IS_DEPTH_STENCIL )
  9203. {
  9204. return GetTexture( textureHandle ).GetDepthStencilSurface() != 0;
  9205. }
  9206. else if ( ( GetTexture( textureHandle ).m_NumCopies == 1 && GetTexture( textureHandle ).GetTexture() != 0 ) ||
  9207. ( GetTexture( textureHandle ).m_NumCopies > 1 && GetTexture( textureHandle ).GetTexture( 0 ) != 0 ) )
  9208. {
  9209. return true;
  9210. }
  9211. else
  9212. {
  9213. return false;
  9214. }
  9215. #else
  9216. // query is about texture handle validity, not presence
  9217. // texture handle is allocated, texture may or may not be present
  9218. return true;
  9219. #endif
  9220. }
  9221. //-----------------------------------------------------------------------------
  9222. // Gets the surface associated with a texture (refcount of surface is increased)
  9223. //-----------------------------------------------------------------------------
  9224. IDirect3DSurface* CShaderAPIDx8::GetTextureSurface( ShaderAPITextureHandle_t textureHandle )
  9225. {
  9226. MEM_ALLOC_D3D_CREDIT();
  9227. IDirect3DSurface* pSurface;
  9228. // We'll be modifying this sucka
  9229. AssertValidTextureHandle( textureHandle );
  9230. //APSFIXME
  9231. //tmauer
  9232. //right now the 360 is getting invalid texture hadles here
  9233. // <sergiy> 5/20/2015: There's significant number of crashes in Windows NT - Crash Reports for CShaderAPIDx8::ReadPixelsAsync(int, int, int, int, unsigned char*, ImageFormat, ITexture*, CThreadEvent*)
  9234. // due to this handle being invalid. It may have to do with losing D3D device. Robustifying this code to check if the crashes will end.
  9235. if ( !m_Textures.IsValidIndex( textureHandle ) )
  9236. {
  9237. return NULL;
  9238. }
  9239. Texture_t &tex = GetTexture( textureHandle );
  9240. if ( !( tex.m_Flags & Texture_t::IS_ALLOCATED ) )
  9241. {
  9242. return NULL;
  9243. }
  9244. if ( IsX360() && ( tex.m_Flags & Texture_t::IS_RENDER_TARGET_SURFACE ) )
  9245. {
  9246. pSurface = tex.GetRenderTargetSurface( false );
  9247. pSurface->AddRef();
  9248. return pSurface;
  9249. }
  9250. IDirect3DBaseTexture* pD3DTex = CShaderAPIDx8::GetD3DTexture( textureHandle );
  9251. IDirect3DTexture* pTex = static_cast<IDirect3DTexture*>( pD3DTex );
  9252. Assert( pTex );
  9253. if ( !pTex )
  9254. {
  9255. return NULL;
  9256. }
  9257. HRESULT hr = pTex->GetSurfaceLevel( 0, &pSurface );
  9258. Assert( hr == D3D_OK );
  9259. return pSurface;
  9260. }
  9261. //-----------------------------------------------------------------------------
  9262. // Gets the surface associated with a texture (refcount of surface is increased)
  9263. //-----------------------------------------------------------------------------
  9264. IDirect3DSurface* CShaderAPIDx8::GetDepthTextureSurface( ShaderAPITextureHandle_t textureHandle )
  9265. {
  9266. AssertValidTextureHandle( textureHandle );
  9267. if ( !TextureIsAllocated( textureHandle ) )
  9268. {
  9269. return NULL;
  9270. }
  9271. return GetTexture( textureHandle ).GetDepthStencilSurface();
  9272. }
  9273. //-----------------------------------------------------------------------------
  9274. // Changes the render target
  9275. //-----------------------------------------------------------------------------
  9276. void CShaderAPIDx8::SetRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t colorTextureHandle, ShaderAPITextureHandle_t depthTextureHandle )
  9277. {
  9278. LOCK_SHADERAPI();
  9279. if ( IsDeactivated( ) )
  9280. {
  9281. return;
  9282. }
  9283. #if defined( PIX_INSTRUMENTATION )
  9284. {
  9285. const char *pRT = "Backbuffer";
  9286. const char *pDS = "DefaultDepthStencil";
  9287. if ( colorTextureHandle == SHADER_RENDERTARGET_NONE )
  9288. {
  9289. pRT = "None";
  9290. }
  9291. else if ( colorTextureHandle != SHADER_RENDERTARGET_BACKBUFFER )
  9292. {
  9293. Texture_t &tex = GetTexture( colorTextureHandle );
  9294. pRT = tex.m_DebugName.String();
  9295. }
  9296. if ( depthTextureHandle == SHADER_RENDERTARGET_NONE )
  9297. {
  9298. pDS = "None";
  9299. }
  9300. else if ( depthTextureHandle != SHADER_RENDERTARGET_DEPTHBUFFER )
  9301. {
  9302. Texture_t &tex = GetTexture( depthTextureHandle );
  9303. pDS = tex.m_DebugName.String();
  9304. }
  9305. char buf[256];
  9306. sprintf( buf, "SRT:%s %s", pRT ? pRT : "?", pDS ? pDS : "?" );
  9307. BeginPIXEvent( 0xFFFFFFFF, buf );
  9308. EndPIXEvent();
  9309. }
  9310. #endif
  9311. #if !defined( _X360 )
  9312. RECORD_COMMAND( DX8_TEST_COOPERATIVE_LEVEL, 0 );
  9313. HRESULT hr = Dx9Device()->TestCooperativeLevel();
  9314. if ( hr != D3D_OK )
  9315. {
  9316. MarkDeviceLost();
  9317. return;
  9318. }
  9319. #endif
  9320. IDirect3DSurface* pColorSurface = NULL;
  9321. IDirect3DSurface* pZSurface = NULL;
  9322. RECORD_COMMAND( DX8_SET_RENDER_TARGET, 3 );
  9323. RECORD_INT( nRenderTargetID );
  9324. RECORD_INT( colorTextureHandle );
  9325. RECORD_INT( depthTextureHandle );
  9326. int backBufferIdx = GetIntRenderingParameter( INT_RENDERPARM_BACK_BUFFER_INDEX );
  9327. // The 0th render target defines which depth buffer we are using, so
  9328. // don't bother if we are another render target
  9329. if ( nRenderTargetID > 0 )
  9330. {
  9331. depthTextureHandle = SHADER_RENDERTARGET_NONE;
  9332. }
  9333. // NOTE!!!! If this code changes, also change Dx8SetRenderTarget in playback.cpp
  9334. bool usingTextureTarget = false;
  9335. if ( colorTextureHandle == SHADER_RENDERTARGET_BACKBUFFER )
  9336. {
  9337. pColorSurface = m_pBackBufferSurfaces[ backBufferIdx ];
  9338. // This is just to make the code a little simpler...
  9339. // (simplifies the release logic)
  9340. pColorSurface->AddRef();
  9341. }
  9342. else
  9343. {
  9344. // get the texture (Refcount increases)
  9345. UnbindTexture( colorTextureHandle );
  9346. pColorSurface = GetTextureSurface( colorTextureHandle );
  9347. if ( !pColorSurface )
  9348. {
  9349. return;
  9350. }
  9351. usingTextureTarget = true;
  9352. }
  9353. bool bGetSurfaceLevelZSurface = false;
  9354. if ( depthTextureHandle == SHADER_RENDERTARGET_DEPTHBUFFER )
  9355. {
  9356. // using the default depth buffer
  9357. pZSurface = m_pZBufferSurface;
  9358. // simplify the prologue logic
  9359. pZSurface->AddRef();
  9360. SPEW_REFCOUNT( pZSurface );
  9361. }
  9362. else if ( depthTextureHandle == SHADER_RENDERTARGET_NONE )
  9363. {
  9364. // GR - disable depth buffer
  9365. pZSurface = NULL;
  9366. }
  9367. else
  9368. {
  9369. UnbindTexture( depthTextureHandle );
  9370. Texture_t &tex = GetTexture( depthTextureHandle );
  9371. //Cannot use a depth/stencil surface derived from a texture.
  9372. //Asserting helps get the whole call stack instead of letting the 360 report an error with a partial stack
  9373. Assert( !( IsX360() && (tex.m_Flags & Texture_t::IS_DEPTH_STENCIL_TEXTURE) ) );
  9374. if ( tex.m_Flags & Texture_t::IS_DEPTH_STENCIL )
  9375. {
  9376. pZSurface = GetDepthTextureSurface( depthTextureHandle );
  9377. if ( pZSurface )
  9378. {
  9379. pZSurface->AddRef();
  9380. SPEW_REFCOUNT( pZSurface );
  9381. }
  9382. }
  9383. else
  9384. {
  9385. IDirect3DTexture9 *pD3DTexture = (IDirect3DTexture9*)tex.GetTexture();
  9386. if(pD3DTexture)
  9387. {
  9388. HRESULT hr = pD3DTexture->GetSurfaceLevel( 0, &pZSurface );
  9389. SPEW_REFCOUNT( pZSurface );
  9390. bGetSurfaceLevelZSurface = true;
  9391. }
  9392. else
  9393. {
  9394. pZSurface = NULL;
  9395. Warning("Unexpected NULL texture in CShaderAPIDx8::SetRenderTargetEx()\n");
  9396. }
  9397. }
  9398. if ( !pZSurface )
  9399. {
  9400. // Refcount of color surface was increased above
  9401. pColorSurface->Release();
  9402. return;
  9403. }
  9404. usingTextureTarget = true;
  9405. }
  9406. #ifdef _DEBUG
  9407. if ( pZSurface )
  9408. {
  9409. D3DSURFACE_DESC zSurfaceDesc, colorSurfaceDesc;
  9410. pZSurface->GetDesc( &zSurfaceDesc );
  9411. pColorSurface->GetDesc( &colorSurfaceDesc );
  9412. Assert( colorSurfaceDesc.Width <= zSurfaceDesc.Width );
  9413. Assert( colorSurfaceDesc.Height <= zSurfaceDesc.Height );
  9414. }
  9415. #endif
  9416. // NOTE: The documentation says that SetRenderTarget increases the refcount
  9417. // but it doesn't appear to in practice. If this somehow changes (perhaps
  9418. // in a device-specific manner, we're in trouble).
  9419. bool bSetValidRenderTarget = false;
  9420. if ( IsPC() || !IsX360() )
  9421. {
  9422. if ( pColorSurface == m_pBackBufferSurfaces[backBufferIdx] && nRenderTargetID > 0 )
  9423. {
  9424. // SetRenderTargetEx is overloaded so that if you pass NULL in for anything that
  9425. // isn't the zeroth render target, you effectively disable that MRT index.
  9426. // (Passing in NULL for the zeroth render target means that you want to use the backbuffer
  9427. // as the render target.)
  9428. // hack hack hack!!!!! If the render target id > 0 and the user passed in NULL, disable the render target
  9429. Dx9Device()->SetRenderTarget( nRenderTargetID, NULL );
  9430. }
  9431. else
  9432. {
  9433. Dx9Device()->SetRenderTarget( nRenderTargetID, pColorSurface );
  9434. bSetValidRenderTarget = true;
  9435. }
  9436. }
  9437. else
  9438. {
  9439. Assert( nRenderTargetID == 0 );
  9440. SetRenderTargetInternalXbox( colorTextureHandle );
  9441. bSetValidRenderTarget = true;
  9442. }
  9443. // The 0th render target defines which depth buffer we are using, so
  9444. // don't bother if we are another render target
  9445. if ( nRenderTargetID == 0 )
  9446. {
  9447. SPEW_REFCOUNT( pZSurface );
  9448. Dx9Device()->SetDepthStencilSurface( pZSurface );
  9449. SPEW_REFCOUNT( pZSurface );
  9450. }
  9451. // Only record if we're rendering to a texture or not (and its dimensions) when we actually set a valid render target (or depth-stencil surface).
  9452. // If nRenderTargetID==0, we're always setting at least the depth-stencil surface.
  9453. // Otherwise, only execute this logic when we are actually setting a valid surface.
  9454. if ( ( !nRenderTargetID ) || ( bSetValidRenderTarget ) )
  9455. {
  9456. m_UsingTextureRenderTarget = usingTextureTarget;
  9457. if ( m_UsingTextureRenderTarget )
  9458. {
  9459. D3DSURFACE_DESC desc;
  9460. HRESULT hr;
  9461. if ( !pZSurface )
  9462. {
  9463. hr = pColorSurface->GetDesc( &desc );
  9464. }
  9465. else
  9466. {
  9467. hr = pZSurface->GetDesc( &desc );
  9468. }
  9469. Assert( !FAILED(hr) );
  9470. m_ViewportMaxWidth = desc.Width;
  9471. m_ViewportMaxHeight = desc.Height;
  9472. }
  9473. }
  9474. int ref;
  9475. if ( pZSurface )
  9476. {
  9477. SPEW_REFCOUNT( pZSurface );
  9478. ref = pZSurface->Release();
  9479. SPEW_REFCOUNT( pZSurface );
  9480. Assert( bGetSurfaceLevelZSurface || ref != 0 );
  9481. }
  9482. ref = pColorSurface->Release();
  9483. // Assert( ref != 0 );
  9484. // Changing the render target sets a default viewport.
  9485. // Force an update but preserve the current desired state.
  9486. m_DynamicState.m_Viewport.X = 0;
  9487. m_DynamicState.m_Viewport.Y = 0;
  9488. m_DynamicState.m_Viewport.Width = (DWORD)-1;
  9489. m_DynamicState.m_Viewport.Height = (DWORD)-1;
  9490. ADD_COMMIT_FUNC( COMMIT_PER_DRAW, CommitSetViewports );
  9491. }
  9492. //-----------------------------------------------------------------------------
  9493. // Changes the render target
  9494. //-----------------------------------------------------------------------------
  9495. void CShaderAPIDx8::SetRenderTarget( ShaderAPITextureHandle_t colorTextureHandle, ShaderAPITextureHandle_t depthTextureHandle )
  9496. {
  9497. LOCK_SHADERAPI();
  9498. SetRenderTargetEx( 0, colorTextureHandle, depthTextureHandle );
  9499. }
  9500. //-----------------------------------------------------------------------------
  9501. // Returns the nearest supported format
  9502. //-----------------------------------------------------------------------------
  9503. ImageFormat CShaderAPIDx8::GetNearestSupportedFormat( ImageFormat fmt, bool bFilteringRequired /* = true */ ) const
  9504. {
  9505. return ImageLoader::D3DFormatToImageFormat( FindNearestSupportedFormat( fmt, false, false, bFilteringRequired ) );
  9506. }
  9507. ImageFormat CShaderAPIDx8::GetNearestRenderTargetFormat( ImageFormat fmt ) const
  9508. {
  9509. return ImageLoader::D3DFormatToImageFormat( FindNearestSupportedFormat( fmt, false, true, false ) );
  9510. }
  9511. bool CShaderAPIDx8::DoRenderTargetsNeedSeparateDepthBuffer() const
  9512. {
  9513. LOCK_SHADERAPI();
  9514. return m_PresentParameters.MultiSampleType != D3DMULTISAMPLE_NONE;
  9515. }
  9516. //-----------------------------------------------------------------------------
  9517. // Indicates we're modifying a texture
  9518. //-----------------------------------------------------------------------------
  9519. void CShaderAPIDx8::ModifyTexture( ShaderAPITextureHandle_t textureHandle )
  9520. {
  9521. LOCK_SHADERAPI();
  9522. // Can't do this if we're locked!
  9523. Assert( m_ModifyTextureLockedLevel < 0 );
  9524. AssertValidTextureHandle( textureHandle );
  9525. m_ModifyTextureHandle = textureHandle;
  9526. // If we're got a multi-copy texture, we need to up the current copy count
  9527. Texture_t& tex = GetTexture( textureHandle );
  9528. if (tex.m_NumCopies > 1)
  9529. {
  9530. // Each time we modify a texture, we'll want to switch texture
  9531. // as soon as a TexImage2D call is made...
  9532. tex.m_SwitchNeeded = true;
  9533. }
  9534. }
  9535. //-----------------------------------------------------------------------------
  9536. // Advances the current copy of a texture...
  9537. //-----------------------------------------------------------------------------
  9538. void CShaderAPIDx8::AdvanceCurrentCopy( ShaderAPITextureHandle_t hTexture )
  9539. {
  9540. // May need to switch textures....
  9541. Texture_t& tex = GetTexture( hTexture );
  9542. if (tex.m_NumCopies > 1)
  9543. {
  9544. if (++tex.m_CurrentCopy >= tex.m_NumCopies)
  9545. tex.m_CurrentCopy = 0;
  9546. // When the current copy changes, we need to make sure this texture
  9547. // isn't bound to any stages any more; thereby guaranteeing the new
  9548. // copy will be re-bound.
  9549. UnbindTexture( hTexture );
  9550. }
  9551. }
  9552. //-----------------------------------------------------------------------------
  9553. // Locks, unlocks the current texture
  9554. //-----------------------------------------------------------------------------
  9555. bool CShaderAPIDx8::TexLock( int level, int cubeFaceID, int xOffset, int yOffset,
  9556. int width, int height, CPixelWriter& writer )
  9557. {
  9558. LOCK_SHADERAPI();
  9559. Assert( m_ModifyTextureLockedLevel < 0 );
  9560. ShaderAPITextureHandle_t hTexture = GetModifyTextureHandle();
  9561. if ( !m_Textures.IsValidIndex( hTexture ) )
  9562. return false;
  9563. // This test here just makes sure we don't try to download mipmap levels
  9564. // if we weren't able to create them in the first place
  9565. Texture_t& tex = GetTexture( hTexture );
  9566. if ( level >= tex.m_NumLevels )
  9567. return false;
  9568. // May need to switch textures....
  9569. if ( tex.m_SwitchNeeded )
  9570. {
  9571. AdvanceCurrentCopy( hTexture );
  9572. tex.m_SwitchNeeded = false;
  9573. }
  9574. IDirect3DBaseTexture *pTexture = GetModifyTexture();
  9575. #if defined( _X360 )
  9576. // 360 can't lock a bound texture
  9577. if ( pTexture && pTexture->IsSet( Dx9Device() ) )
  9578. {
  9579. UnbindTexture( hTexture );
  9580. }
  9581. #endif
  9582. bool bOK = LockTexture( hTexture, tex.m_CurrentCopy, pTexture,
  9583. level, (D3DCUBEMAP_FACES)cubeFaceID, xOffset, yOffset, width, height, false, writer );
  9584. if ( bOK )
  9585. {
  9586. m_ModifyTextureLockedLevel = level;
  9587. m_ModifyTextureLockedFace = cubeFaceID;
  9588. }
  9589. return bOK;
  9590. }
  9591. void CShaderAPIDx8::TexUnlock( )
  9592. {
  9593. LOCK_SHADERAPI();
  9594. if ( m_ModifyTextureLockedLevel >= 0 )
  9595. {
  9596. Texture_t& tex = GetTexture( GetModifyTextureHandle() );
  9597. UnlockTexture( GetModifyTextureHandle(), tex.m_CurrentCopy, GetModifyTexture(),
  9598. m_ModifyTextureLockedLevel, (D3DCUBEMAP_FACES)(int)m_ModifyTextureLockedFace );
  9599. m_ModifyTextureLockedLevel = -1;
  9600. }
  9601. }
  9602. //-----------------------------------------------------------------------------
  9603. // Texture image upload
  9604. //-----------------------------------------------------------------------------
  9605. void CShaderAPIDx8::TexImage2D(
  9606. int level,
  9607. int cubeFaceID,
  9608. ImageFormat dstFormat,
  9609. int z,
  9610. int width,
  9611. int height,
  9612. ImageFormat srcFormat,
  9613. bool bSrcIsTiled,
  9614. void *pSrcData )
  9615. {
  9616. LOCK_SHADERAPI();
  9617. Assert( pSrcData );
  9618. AssertValidTextureHandle( GetModifyTextureHandle() );
  9619. if ( !m_Textures.IsValidIndex( GetModifyTextureHandle() ) )
  9620. return;
  9621. Assert( (width <= g_pHardwareConfig->Caps().m_MaxTextureWidth) && (height <= g_pHardwareConfig->Caps().m_MaxTextureHeight) );
  9622. // This test here just makes sure we don't try to download mipmap levels
  9623. // if we weren't able to create them in the first place
  9624. Texture_t& tex = GetTexture( GetModifyTextureHandle() );
  9625. if ( level >= tex.m_NumLevels )
  9626. return;
  9627. // May need to switch textures....
  9628. if (tex.m_SwitchNeeded)
  9629. {
  9630. AdvanceCurrentCopy( GetModifyTextureHandle() );
  9631. tex.m_SwitchNeeded = false;
  9632. }
  9633. TextureLoadInfo_t info;
  9634. info.m_TextureHandle = GetModifyTextureHandle();
  9635. info.m_pTexture = GetModifyTexture();
  9636. info.m_nLevel = level;
  9637. info.m_nCopy = tex.m_CurrentCopy;
  9638. info.m_CubeFaceID = (D3DCUBEMAP_FACES)cubeFaceID;
  9639. info.m_nWidth = width;
  9640. info.m_nHeight = height;
  9641. info.m_nZOffset = z;
  9642. info.m_SrcFormat = srcFormat;
  9643. info.m_pSrcData = (unsigned char *)pSrcData;
  9644. #if defined( _X360 )
  9645. info.m_bSrcIsTiled = bSrcIsTiled;
  9646. info.m_bCanConvertFormat = ( tex.m_Flags & Texture_t::CAN_CONVERT_FORMAT ) != 0;
  9647. #endif
  9648. LoadTexture( info );
  9649. SetModifyTexture( info.m_pTexture );
  9650. }
  9651. //-----------------------------------------------------------------------------
  9652. // Upload to a sub-piece of a texture
  9653. //-----------------------------------------------------------------------------
  9654. void CShaderAPIDx8::TexSubImage2D(
  9655. int level,
  9656. int cubeFaceID,
  9657. int xOffset,
  9658. int yOffset,
  9659. int zOffset,
  9660. int width,
  9661. int height,
  9662. ImageFormat srcFormat,
  9663. int srcStride,
  9664. bool bSrcIsTiled,
  9665. void *pSrcData )
  9666. {
  9667. LOCK_SHADERAPI();
  9668. Assert( pSrcData );
  9669. AssertValidTextureHandle( GetModifyTextureHandle() );
  9670. if ( !m_Textures.IsValidIndex( GetModifyTextureHandle() ) )
  9671. return;
  9672. // NOTE: This can only be done with procedural textures if this method is
  9673. // being used to download the entire texture, cause last frame's partial update
  9674. // may be in a completely different texture! Sadly, I don't have all of the
  9675. // information I need, but I can at least check a couple things....
  9676. #ifdef _DEBUG
  9677. if ( GetTexture( GetModifyTextureHandle() ).m_NumCopies > 1 )
  9678. {
  9679. Assert( (xOffset == 0) && (yOffset == 0) );
  9680. }
  9681. #endif
  9682. // This test here just makes sure we don't try to download mipmap levels
  9683. // if we weren't able to create them in the first place
  9684. Texture_t& tex = GetTexture( GetModifyTextureHandle() );
  9685. if ( level >= tex.m_NumLevels )
  9686. {
  9687. return;
  9688. }
  9689. // May need to switch textures....
  9690. if ( tex.m_SwitchNeeded )
  9691. {
  9692. AdvanceCurrentCopy( GetModifyTextureHandle() );
  9693. tex.m_SwitchNeeded = false;
  9694. }
  9695. TextureLoadInfo_t info;
  9696. info.m_TextureHandle = GetModifyTextureHandle();
  9697. info.m_pTexture = GetModifyTexture();
  9698. info.m_nLevel = level;
  9699. info.m_nCopy = tex.m_CurrentCopy;
  9700. info.m_CubeFaceID = (D3DCUBEMAP_FACES)cubeFaceID;
  9701. info.m_nWidth = width;
  9702. info.m_nHeight = height;
  9703. info.m_nZOffset = zOffset;
  9704. info.m_SrcFormat = srcFormat;
  9705. info.m_pSrcData = (unsigned char *)pSrcData;
  9706. #if defined( _X360 )
  9707. info.m_bSrcIsTiled = bSrcIsTiled;
  9708. info.m_bCanConvertFormat = ( tex.m_Flags & Texture_t::CAN_CONVERT_FORMAT ) != 0;
  9709. #endif
  9710. LoadSubTexture( info, xOffset, yOffset, srcStride );
  9711. }
  9712. //-----------------------------------------------------------------------------
  9713. // Upload to a default pool texture from a sysmem texture
  9714. //-----------------------------------------------------------------------------
  9715. void CShaderAPIDx8::UpdateTexture( int xOffset, int yOffset, int w, int h, ShaderAPITextureHandle_t hDstTexture, ShaderAPITextureHandle_t hSrcTexture )
  9716. {
  9717. Assert( IsPC() );
  9718. LOCK_SHADERAPI();
  9719. AssertValidTextureHandle( hDstTexture );
  9720. if ( !m_Textures.IsValidIndex( hDstTexture ) )
  9721. return;
  9722. AssertValidTextureHandle( hSrcTexture );
  9723. if ( !m_Textures.IsValidIndex( hSrcTexture ) )
  9724. return;
  9725. IDirect3DTexture *pDstTexture = (IDirect3DTexture *) g_ShaderAPIDX8.GetTexture( hDstTexture ).GetTexture();
  9726. IDirect3DSurface9 *pDstSurface;
  9727. HRESULT hr = pDstTexture->GetSurfaceLevel( 0, &pDstSurface );
  9728. Assert( !FAILED( hr ) );
  9729. IDirect3DTexture *pSrcTexture = (IDirect3DTexture *) g_ShaderAPIDX8.GetTexture( hSrcTexture ).GetTexture();
  9730. IDirect3DSurface9 *pSrcSurface;
  9731. hr = pSrcTexture->GetSurfaceLevel( 0, &pSrcSurface );
  9732. Assert( !FAILED( hr ) );
  9733. RECT srcRect = { xOffset, yOffset, w, h };
  9734. POINT dstPoint = { 0, 0 };
  9735. #if ( defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION ) )
  9736. AssertMsg( false, "Not supported on Xbox 360 or Posix." );
  9737. #else
  9738. hr = Dx9Device()->UpdateSurface( pSrcSurface, &srcRect, pDstSurface, &dstPoint );
  9739. Assert( !FAILED( hr ) );
  9740. #endif
  9741. pDstSurface->Release(); // The GetSurfaceLevel calls incremented ref count
  9742. pSrcSurface->Release();
  9743. }
  9744. void *CShaderAPIDx8::LockTex( ShaderAPITextureHandle_t hTexture )
  9745. {
  9746. IDirect3DTexture *pTex = (IDirect3DTexture *) g_ShaderAPIDX8.GetTexture( hTexture ).GetTexture();
  9747. IDirect3DSurface9 *pSurf;
  9748. HRESULT hr = pTex->GetSurfaceLevel( 0, &pSurf );
  9749. Assert( !FAILED( hr ) );
  9750. D3DLOCKED_RECT lockedRect;
  9751. hr = pSurf->LockRect( &lockedRect, NULL, D3DLOCK_NO_DIRTY_UPDATE );
  9752. Assert( !FAILED( hr ) );
  9753. pSurf->Release(); // The GetSurfaceLevel call incremented ref count
  9754. return lockedRect.pBits;
  9755. }
  9756. void CShaderAPIDx8::UnlockTex( ShaderAPITextureHandle_t hTexture )
  9757. {
  9758. IDirect3DTexture *pTex = (IDirect3DTexture *) g_ShaderAPIDX8.GetTexture( hTexture ).GetTexture();
  9759. IDirect3DSurface9 *pSurf;
  9760. HRESULT hr = pTex->GetSurfaceLevel( 0, &pSurf );
  9761. Assert( !FAILED( hr ) );
  9762. hr = pSurf->UnlockRect();
  9763. Assert( !FAILED( hr ) );
  9764. pSurf->Release(); // The GetSurfaceLevel call incremented ref count
  9765. }
  9766. //-----------------------------------------------------------------------------
  9767. // Is the texture resident?
  9768. //-----------------------------------------------------------------------------
  9769. bool CShaderAPIDx8::IsTextureResident( ShaderAPITextureHandle_t textureHandle )
  9770. {
  9771. return true;
  9772. }
  9773. //-----------------------------------------------------------------------------
  9774. // Level of anisotropic filtering
  9775. //-----------------------------------------------------------------------------
  9776. ConVar mat_aniso_disable( "mat_aniso_disable", "0", FCVAR_CHEAT, "NOTE: You must change mat_forceaniso after changing this convar for this to take effect" );
  9777. void CShaderAPIDx8::SetAnisotropicLevel( int nAnisotropyLevel )
  9778. {
  9779. LOCK_SHADERAPI();
  9780. // NOTE: This must be called before the rest of the code in this function so
  9781. // anisotropic can be set per-texture to force it on! This will also avoid
  9782. // a possible infinite loop that existed before.
  9783. g_pShaderUtil->NoteAnisotropicLevel( nAnisotropyLevel );
  9784. // Never set this to 1. In the case we want it set to 1, we will use this to override
  9785. // aniso per-texture, so set it to something reasonable.
  9786. if ( mat_aniso_disable.GetInt() == 1 )
  9787. {
  9788. // Don't allow any aniso at all
  9789. nAnisotropyLevel = 1;
  9790. }
  9791. else
  9792. {
  9793. int nAnisotropyLevelOverride = 1;
  9794. if ( IsGameConsole() )
  9795. {
  9796. nAnisotropyLevelOverride = 4;
  9797. }
  9798. else
  9799. {
  9800. // Set it to 1/2 the max but at least 2
  9801. nAnisotropyLevelOverride = MAX( 2, g_pHardwareConfig->Caps().m_nMaxAnisotropy / 2 );
  9802. }
  9803. // Use the larger value
  9804. nAnisotropyLevel = MAX( nAnisotropyLevel, nAnisotropyLevelOverride );
  9805. }
  9806. // Make sure the value is in range
  9807. nAnisotropyLevel = MIN( nAnisotropyLevel, g_pHardwareConfig->Caps().m_nMaxAnisotropy );
  9808. // Set the D3D max anisotropy state for all samplers
  9809. for ( int i = 0; i < g_pHardwareConfig->Caps().m_NumSamplers; ++i)
  9810. {
  9811. SamplerState(i).m_nAnisotropicLevel = nAnisotropyLevel;
  9812. SetSamplerState( i, D3DSAMP_MAXANISOTROPY, SamplerState(i).m_nAnisotropicLevel );
  9813. }
  9814. }
  9815. //-----------------------------------------------------------------------------
  9816. // Sets the priority
  9817. //-----------------------------------------------------------------------------
  9818. void CShaderAPIDx8::TexSetPriority( int priority )
  9819. {
  9820. #if !defined( _X360 )
  9821. LOCK_SHADERAPI();
  9822. // A hint to the cacher...
  9823. ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
  9824. if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
  9825. return;
  9826. Texture_t& tex = GetTexture( hModifyTexture );
  9827. if ( tex.m_NumCopies > 1 )
  9828. {
  9829. for (int i = 0; i < tex.m_NumCopies; ++i)
  9830. tex.GetTexture( i )->SetPriority( priority );
  9831. }
  9832. else if ( tex.GetTexture() ) // null check
  9833. {
  9834. tex.GetTexture()->SetPriority( priority );
  9835. }
  9836. #endif
  9837. }
  9838. //-----------------------------------------------------------------------------
  9839. // Texturemapping state
  9840. //-----------------------------------------------------------------------------
  9841. void CShaderAPIDx8::TexWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode )
  9842. {
  9843. LOCK_SHADERAPI();
  9844. ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
  9845. if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
  9846. return;
  9847. D3DTEXTUREADDRESS address;
  9848. switch( wrapMode )
  9849. {
  9850. case SHADER_TEXWRAPMODE_CLAMP:
  9851. address = D3DTADDRESS_CLAMP;
  9852. break;
  9853. case SHADER_TEXWRAPMODE_REPEAT:
  9854. address = D3DTADDRESS_WRAP;
  9855. break;
  9856. case SHADER_TEXWRAPMODE_BORDER:
  9857. address = D3DTADDRESS_BORDER;
  9858. break;
  9859. default:
  9860. address = D3DTADDRESS_CLAMP;
  9861. Warning( "CShaderAPIDx8::TexWrap: unknown wrapMode\n" );
  9862. break;
  9863. }
  9864. switch( coord )
  9865. {
  9866. case SHADER_TEXCOORD_S:
  9867. GetTexture( hModifyTexture ).m_UTexWrap = address;
  9868. break;
  9869. case SHADER_TEXCOORD_T:
  9870. GetTexture( hModifyTexture ).m_VTexWrap = address;
  9871. break;
  9872. case SHADER_TEXCOORD_U:
  9873. GetTexture( hModifyTexture ).m_WTexWrap = address;
  9874. break;
  9875. default:
  9876. Warning( "CShaderAPIDx8::TexWrap: unknown coord\n" );
  9877. break;
  9878. }
  9879. }
  9880. void CShaderAPIDx8::TexMinFilter( ShaderTexFilterMode_t texFilterMode )
  9881. {
  9882. LOCK_SHADERAPI();
  9883. ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
  9884. if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
  9885. return;
  9886. switch( texFilterMode )
  9887. {
  9888. case SHADER_TEXFILTERMODE_NEAREST:
  9889. GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_POINT;
  9890. GetTexture( hModifyTexture ).m_MipFilter = D3DTEXF_NONE;
  9891. break;
  9892. case SHADER_TEXFILTERMODE_LINEAR:
  9893. GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_LINEAR;
  9894. GetTexture( hModifyTexture ).m_MipFilter = D3DTEXF_NONE;
  9895. break;
  9896. case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST:
  9897. GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_POINT;
  9898. GetTexture( hModifyTexture ).m_MipFilter =
  9899. GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_POINT : D3DTEXF_NONE;
  9900. break;
  9901. case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST:
  9902. GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_LINEAR;
  9903. GetTexture( hModifyTexture ).m_MipFilter =
  9904. GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_POINT : D3DTEXF_NONE;
  9905. break;
  9906. case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR:
  9907. GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_POINT;
  9908. GetTexture( hModifyTexture ).m_MipFilter =
  9909. GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_LINEAR : D3DTEXF_NONE;
  9910. break;
  9911. case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR:
  9912. GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_LINEAR;
  9913. GetTexture( hModifyTexture ).m_MipFilter =
  9914. GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_LINEAR : D3DTEXF_NONE;
  9915. break;
  9916. case SHADER_TEXFILTERMODE_ANISOTROPIC:
  9917. GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_ANISOTROPIC;
  9918. GetTexture( hModifyTexture ).m_MipFilter =
  9919. GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_LINEAR : D3DTEXF_NONE;
  9920. break;
  9921. default:
  9922. Warning( "CShaderAPIDx8::TexMinFilter: Unknown texFilterMode\n" );
  9923. break;
  9924. }
  9925. }
  9926. void CShaderAPIDx8::TexMagFilter( ShaderTexFilterMode_t texFilterMode )
  9927. {
  9928. LOCK_SHADERAPI();
  9929. ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
  9930. if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
  9931. return;
  9932. switch( texFilterMode )
  9933. {
  9934. case SHADER_TEXFILTERMODE_NEAREST:
  9935. GetTexture( hModifyTexture ).m_MagFilter = D3DTEXF_POINT;
  9936. break;
  9937. case SHADER_TEXFILTERMODE_LINEAR:
  9938. GetTexture( hModifyTexture ).m_MagFilter = D3DTEXF_LINEAR;
  9939. break;
  9940. case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST:
  9941. Warning( "CShaderAPIDx8::TexMagFilter: SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST is invalid\n" );
  9942. break;
  9943. case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST:
  9944. Warning( "CShaderAPIDx8::TexMagFilter: SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST is invalid\n" );
  9945. break;
  9946. case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR:
  9947. Warning( "CShaderAPIDx8::TexMagFilter: SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR is invalid\n" );
  9948. break;
  9949. case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR:
  9950. Warning( "CShaderAPIDx8::TexMagFilter: SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR is invalid\n" );
  9951. break;
  9952. case SHADER_TEXFILTERMODE_ANISOTROPIC:
  9953. GetTexture( hModifyTexture ).m_MagFilter = g_pHardwareConfig->Caps().m_bSupportsMagAnisotropicFiltering ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR;
  9954. break;
  9955. default:
  9956. Warning( "CShaderAPIDx8::TexMAGFilter: Unknown texFilterMode\n" );
  9957. break;
  9958. }
  9959. }
  9960. //-----------------------------------------------------------------------------
  9961. // Gets the matrix stack from the matrix mode
  9962. //-----------------------------------------------------------------------------
  9963. int CShaderAPIDx8::GetMatrixStack( MaterialMatrixMode_t mode ) const
  9964. {
  9965. Assert( mode >= 0 && mode < NUM_MATRIX_MODES );
  9966. return mode;
  9967. }
  9968. //-----------------------------------------------------------------------------
  9969. // lighting related methods
  9970. //-----------------------------------------------------------------------------
  9971. void CShaderAPIDx8::SetLightingState( const MaterialLightingState_t& state )
  9972. {
  9973. bool bAmbientChanged = Q_memcmp( m_DynamicState.m_LightingState.m_vecAmbientCube, state.m_vecAmbientCube, sizeof(state.m_vecAmbientCube) ) != 0;
  9974. bool bLightsChanged = ( state.m_nLocalLightCount != 0 ) || ( m_DynamicState.m_LightingState.m_nLocalLightCount != 0 );
  9975. if ( !bAmbientChanged && !bLightsChanged )
  9976. return;
  9977. m_DynamicState.m_LightingState = state;
  9978. if ( bAmbientChanged )
  9979. {
  9980. m_DynamicState.m_InstanceInfo.m_bAmbientCubeCompiled = false;
  9981. }
  9982. if ( bLightsChanged )
  9983. {
  9984. m_DynamicState.m_InstanceInfo.m_bPixelShaderLocalLightsCompiled = false;
  9985. m_DynamicState.m_InstanceInfo.m_bVertexShaderLocalLightsCompiled = false;
  9986. m_DynamicState.m_InstanceInfo.m_bSetLightVertexShaderConstants = false;
  9987. //#ifdef _DEBUG
  9988. for ( int i = 0; i < m_DynamicState.m_LightingState.m_nLocalLightCount; ++i )
  9989. {
  9990. // NOTE: This means we haven't set the light up correctly
  9991. if ( ( m_DynamicState.m_LightingState.m_pLocalLightDesc[i].m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED ) == 0 )
  9992. {
  9993. Warning( "Client code forgot to call LightDesc_t::RecalculateDerivedValues\n" );
  9994. m_DynamicState.m_LightingState.m_pLocalLightDesc[i].RecalculateDerivedValues();
  9995. }
  9996. Assert( m_DynamicState.m_LightingState.m_pLocalLightDesc[i].m_Type != MATERIAL_LIGHT_DISABLE );
  9997. }
  9998. //#endif
  9999. }
  10000. }
  10001. void CShaderAPIDx8::SetLightingOrigin( Vector vLightingOrigin )
  10002. {
  10003. m_DynamicState.m_LightingState.m_vecLightingOrigin = vLightingOrigin;
  10004. }
  10005. //#define NO_LOCAL_LIGHTS
  10006. void CShaderAPIDx8::SetLights( int nCount, const LightDesc_t* pDesc )
  10007. {
  10008. LOCK_SHADERAPI();
  10009. #ifdef NO_LOCAL_LIGHTS
  10010. nCount = 0;
  10011. #endif
  10012. int nMaxLight = MIN( g_pHardwareConfig->Caps().m_MaxNumLights, MATERIAL_MAX_LIGHT_COUNT );
  10013. nCount = MIN( nMaxLight, nCount );
  10014. m_DynamicState.m_LightingState.m_nLocalLightCount = nCount;
  10015. if ( nCount > 0 )
  10016. {
  10017. memcpy( m_DynamicState.m_LightingState.m_pLocalLightDesc, pDesc, nCount * sizeof(LightDesc_t) );
  10018. #ifdef _DEBUG
  10019. for ( int i = 0; i < nCount; ++i )
  10020. {
  10021. Assert( m_DynamicState.m_LightingState.m_pLocalLightDesc[i].m_Type != MATERIAL_LIGHT_DISABLE );
  10022. }
  10023. #endif
  10024. }
  10025. m_DynamicState.m_InstanceInfo.m_bPixelShaderLocalLightsCompiled = false;
  10026. m_DynamicState.m_InstanceInfo.m_bVertexShaderLocalLightsCompiled = false;
  10027. m_DynamicState.m_InstanceInfo.m_bSetLightVertexShaderConstants = false;
  10028. }
  10029. void CShaderAPIDx8::DisableAllLocalLights()
  10030. {
  10031. LOCK_SHADERAPI();
  10032. if ( m_DynamicState.m_LightingState.m_nLocalLightCount != 0 )
  10033. {
  10034. m_DynamicState.m_LightingState.m_nLocalLightCount = 0;
  10035. m_DynamicState.m_InstanceInfo.m_bPixelShaderLocalLightsCompiled = false;
  10036. m_DynamicState.m_InstanceInfo.m_bVertexShaderLocalLightsCompiled = false;
  10037. m_DynamicState.m_InstanceInfo.m_bSetLightVertexShaderConstants = false;
  10038. }
  10039. }
  10040. //-----------------------------------------------------------------------------
  10041. // Ambient cube
  10042. //-----------------------------------------------------------------------------
  10043. //#define NO_AMBIENT_CUBE 1
  10044. void CShaderAPIDx8::SetAmbientLightCube( Vector4D cube[6] )
  10045. {
  10046. LOCK_SHADERAPI();
  10047. /*
  10048. int i;
  10049. for( i = 0; i < 6; i++ )
  10050. {
  10051. ColorClamp( cube[i].AsVector3D() );
  10052. // if( i == 0 )
  10053. // {
  10054. // Warning( "%d: %f %f %f\n", i, cube[i][0], cube[i][1], cube[i][2] );
  10055. // }
  10056. }
  10057. */
  10058. if ( memcmp(&m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[0][0], cube, 6 * sizeof(Vector4D)) )
  10059. {
  10060. memcpy( &m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[0][0], cube, 6 * sizeof(Vector4D) );
  10061. #ifdef NO_AMBIENT_CUBE
  10062. memset( &m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[0][0], 0, 6 * sizeof(Vector4D) );
  10063. #endif
  10064. //#define DEBUG_AMBIENT_CUBE
  10065. #ifdef DEBUG_AMBIENT_CUBE
  10066. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[0][0] = 1.0f;
  10067. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[0][1] = 0.0f;
  10068. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[0][2] = 0.0f;
  10069. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[1][0] = 0.0f;
  10070. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[1][1] = 1.0f;
  10071. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[1][2] = 0.0f;
  10072. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[2][0] = 0.0f;
  10073. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[2][1] = 0.0f;
  10074. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[2][2] = 1.0f;
  10075. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[3][0] = 1.0f;
  10076. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[3][1] = 0.0f;
  10077. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[3][2] = 1.0f;
  10078. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[4][0] = 1.0f;
  10079. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[4][1] = 1.0f;
  10080. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[4][2] = 0.0f;
  10081. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[5][0] = 0.0f;
  10082. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[5][1] = 1.0f;
  10083. m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[5][2] = 1.0f;
  10084. #endif
  10085. // Copy into other state
  10086. for ( int i = 0; i < 6; ++i )
  10087. {
  10088. m_DynamicState.m_LightingState.m_vecAmbientCube[i] = m_DynamicState.m_CompiledLightingState.m_AmbientLightCube[i].AsVector3D();
  10089. }
  10090. m_DynamicState.m_InstanceInfo.m_bAmbientCubeCompiled = true;
  10091. }
  10092. }
  10093. void CShaderAPIDx8::SetVertexShaderStateAmbientLightCube( int nRegister, CompiledLightingState_t *pLightingState )
  10094. {
  10095. float *pCubeBase = pLightingState->m_AmbientLightCube[0].Base();
  10096. SetVertexShaderConstantInternal( nRegister, pCubeBase, 6 );
  10097. }
  10098. void CShaderAPIDx8::SetPixelShaderStateAmbientLightCube( int nRegister, CompiledLightingState_t *pLightingState )
  10099. {
  10100. float *pCubeBase = pLightingState->m_AmbientLightCube[0].Base();
  10101. SetPixelShaderConstantInternal( nRegister, pCubeBase, 6 );
  10102. }
  10103. float CShaderAPIDx8::GetAmbientLightCubeLuminance( MaterialLightingState_t *pLightingState )
  10104. {
  10105. if ( !pLightingState )
  10106. return 0.0f;
  10107. Vector vLuminance( 0.3f, 0.59f, 0.11f );
  10108. float fLuminance = 0.0f;
  10109. for (int i=0; i<6; i++)
  10110. {
  10111. fLuminance += vLuminance.Dot( pLightingState->m_vecAmbientCube[i] );
  10112. }
  10113. return fLuminance / 6.0f;
  10114. }
  10115. static inline RECT* RectToRECT( Rect_t *pSrcRect, RECT &dstRect )
  10116. {
  10117. if ( !pSrcRect )
  10118. return NULL;
  10119. dstRect.left = pSrcRect->x;
  10120. dstRect.top = pSrcRect->y;
  10121. dstRect.right = pSrcRect->x + pSrcRect->width;
  10122. dstRect.bottom = pSrcRect->y + pSrcRect->height;
  10123. return &dstRect;
  10124. }
  10125. // special code for RESZ resolve trick on ATI & Intel
  10126. #define RESZ_CODE 0x7fa05000
  10127. struct sRESZDummyVB
  10128. {
  10129. float pos[ 3 ];
  10130. };
  10131. static sRESZDummyVB gRESZDummyVB[ 1 ] = { 0.0f, 0.0f, 0.0f };
  10132. void CShaderAPIDx8::CopyRenderTargetToTextureEx( ShaderAPITextureHandle_t textureHandle, int nRenderTargetID, Rect_t *pSrcRect, Rect_t *pDstRect )
  10133. {
  10134. LOCK_SHADERAPI();
  10135. VPROF_BUDGET( "CShaderAPIDx8::CopyRenderTargetToTexture", "Refraction overhead" );
  10136. if ( !TextureIsAllocated( textureHandle ) )
  10137. return;
  10138. #if defined( PIX_INSTRUMENTATION )
  10139. {
  10140. const char *pRT = ( nRenderTargetID < 0 ) ? "DS" : "RT";
  10141. if ( textureHandle == SHADER_RENDERTARGET_NONE )
  10142. {
  10143. pRT = "None";
  10144. }
  10145. else if ( textureHandle != SHADER_RENDERTARGET_BACKBUFFER )
  10146. {
  10147. Texture_t &tex = GetTexture( textureHandle );
  10148. pRT = tex.m_DebugName.String();
  10149. }
  10150. char buf[256];
  10151. sprintf( buf, "CopyRTToTexture:%s", pRT ? pRT : "?" );
  10152. BeginPIXEvent( 0xFFFFFFFF, buf );
  10153. EndPIXEvent();
  10154. }
  10155. #endif
  10156. // Don't flush here!! If you have to flush here, then there is a driver bug.
  10157. // FlushHardware( );
  10158. AssertValidTextureHandle( textureHandle );
  10159. Texture_t *pTexture = &GetTexture( textureHandle );
  10160. Assert( pTexture );
  10161. IDirect3DTexture *pD3DTexture = (IDirect3DTexture *)pTexture->GetTexture();
  10162. Assert( pD3DTexture );
  10163. if ( !pD3DTexture )
  10164. {
  10165. Warning("Unexpected NULL texture in CShaderAPIDx8::CopyRenderTargetToTextureEx()\n");
  10166. return;
  10167. }
  10168. #if defined( _PS3 )
  10169. IDirect3DSurface *pDstSurf;
  10170. RECT srcRect, dstRect;
  10171. HRESULT hr = pD3DTexture->GetSurfaceLevel( 0, &pDstSurf );
  10172. Assert( !FAILED( hr ) );
  10173. if ( FAILED( hr ) )
  10174. {
  10175. return;
  10176. }
  10177. // On PS3, we use some openGL functionality to blit one of the currently-bound ender targets to the given texture.
  10178. // Like Xbox360, this cannot actually stretch the render target; we simply ignore the destination rect width/height.
  10179. hr = Dx9Device()->StretchRect( ( IDirect3DSurface9 * )nRenderTargetID, RectToRECT( pSrcRect, srcRect ),
  10180. pDstSurf, RectToRECT( pDstRect, dstRect ), D3DTEXF_LINEAR );
  10181. pDstSurf->Release();
  10182. Assert( !FAILED( hr ) );
  10183. #elif defined( _WIN32 ) && !defined( DX_TO_GL_ABSTRACTION )
  10184. static ConVarRef mat_resolveFullFrameDepth( "mat_resolveFullFrameDepth" );
  10185. if ( ( nRenderTargetID == -1 ) && g_pHardwareConfig->SupportsResolveDepth() && g_pHardwareConfig->HasFullResolutionDepthTexture() )
  10186. {
  10187. // z buffer resolve tricks
  10188. /*
  10189. not supporting this path yet
  10190. benefit is no depth resolve required (if MSAA off)
  10191. downside is risk of using/modifying depth buffer while rendering (now or in the future), and in managing depth surfaces - resolve at this stage is a much cleaner/safer way of using depth
  10192. if ( g_pHardwareConfig->ActualCaps().m_bSupportsINTZ && ( config.m_nAASamples <= 1 ) )
  10193. {
  10194. // Supports INTZ and MSAA must be OFF
  10195. // Can 'use' the depth stencil surface as is, without need to resolve
  10196. // nothing to do here other than to check that the current DepthStencilSurface and DepthTexture are bound with our INTZ texture
  10197. }
  10198. else
  10199. */
  10200. if ( g_pHardwareConfig->ActualCaps().m_bSupportsRESZ )
  10201. {
  10202. // Supports RESZ (ATI and Intel only)
  10203. // Use a dummy draw call to set sampler 0 to our destination depth texture
  10204. // and set the pointsize renderstate to RESZ_CODE in order to perform the resolve
  10205. // Works with or without MSAA
  10206. Dx9Device()->SetVertexShader( NULL );
  10207. Dx9Device()->SetPixelShader( NULL );
  10208. Dx9Device()->SetFVF( D3DFVF_XYZ );
  10209. // Bind depth stencil texture to texture sampler 0
  10210. Dx9Device()->SetTexture( 0, pD3DTexture );
  10211. // Perform a dummy draw call to ensure texture sampler 0 is set before the resolve is triggered
  10212. // Vertex declaration and shaders may need to be adjusted to ensure no debug error message is produced
  10213. SetRenderStateForce( D3DRS_ZENABLE, FALSE );
  10214. SetRenderStateForce( D3DRS_ZWRITEENABLE, FALSE );
  10215. SetRenderStateForce( D3DRS_COLORWRITEENABLE, 0 );
  10216. Dx9Device()->DrawPrimitiveUP_RESZ( &gRESZDummyVB );
  10217. SetRenderStateForce( D3DRS_ZWRITEENABLE, TRUE );
  10218. SetRenderStateForce( D3DRS_ZENABLE, TRUE );
  10219. SetRenderStateForce( D3DRS_COLORWRITEENABLE, 0x0F );
  10220. // Trigger the depth buffer resolve; after this call texture sampler 0
  10221. // will contain the contents of the resolve operation
  10222. SetRenderStateForce( D3DRS_POINTSIZE, RESZ_CODE );
  10223. // This hack to fix resz hack, has been found by Maksym Bezus
  10224. // Without this line resz will be resolved only for first frame
  10225. SetRenderStateForce( D3DRS_POINTSIZE, 0 );
  10226. // reset vertex decl, fvf
  10227. VertexFormat_t vertexFormat = MeshMgr()->GetCurrentVertexFormat();
  10228. m_DynamicState.m_pVertexDecl = NULL;
  10229. SetVertexDecl( vertexFormat, false, false, false, false, NULL );
  10230. // reset VS/PS
  10231. ShaderManager()->ResetShaderState();
  10232. // reset bound texture
  10233. SamplerState( 0 ).m_BoundTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
  10234. Dx9Device()->SetTexture( 0, 0 );
  10235. }
  10236. else if ( g_pHardwareConfig->ActualCaps().m_VendorID == VENDORID_NVIDIA )
  10237. {
  10238. // Use NvAPI_D3D9_StretchRectEx to perform the resolve
  10239. // Works with or without MSAA
  10240. TM_ZONE( TELEMETRY_LEVEL1, TMZF_NONE, "NVIDIA Setup Resolve" );
  10241. Assert( m_pZBufferSurface );
  10242. if ( m_pNVAPI_registeredDepthStencilSurface != m_pZBufferSurface )
  10243. {
  10244. SPEW_REFCOUNT( m_pZBufferSurface );
  10245. NvAPI_D3D9_RegisterResource( m_pZBufferSurface );
  10246. SPEW_REFCOUNT( m_pZBufferSurface );
  10247. if ( m_pNVAPI_registeredDepthStencilSurface != NULL )
  10248. {
  10249. // Unregister old one if there is any
  10250. SPEW_REFCOUNT( m_pNVAPI_registeredDepthStencilSurface );
  10251. NvAPI_D3D9_UnregisterResource( m_pNVAPI_registeredDepthStencilSurface );
  10252. SPEW_REFCOUNT( m_pNVAPI_registeredDepthStencilSurface );
  10253. }
  10254. m_pNVAPI_registeredDepthStencilSurface = m_pZBufferSurface;
  10255. }
  10256. if ( m_pNVAPI_registeredDepthTexture != pD3DTexture )
  10257. {
  10258. SPEW_REFCOUNT( pD3DTexture );
  10259. NvAPI_D3D9_RegisterResource( pD3DTexture );
  10260. SPEW_REFCOUNT( pD3DTexture );
  10261. if ( m_pNVAPI_registeredDepthTexture != NULL )
  10262. {
  10263. // Unregister old one if there is any
  10264. SPEW_REFCOUNT( m_pNVAPI_registeredDepthStencilSurface );
  10265. NvAPI_D3D9_UnregisterResource( m_pNVAPI_registeredDepthTexture );
  10266. SPEW_REFCOUNT( m_pNVAPI_registeredDepthStencilSurface );
  10267. }
  10268. m_pNVAPI_registeredDepthTexture = pD3DTexture;
  10269. }
  10270. // Resolve
  10271. SPEW_REFCOUNT( m_pZBufferSurface );
  10272. Dx9Device()->StretchRectEx_NvAPI( m_pZBufferSurface, NULL, pD3DTexture, NULL, D3DTEXF_POINT );
  10273. SPEW_REFCOUNT( m_pZBufferSurface );
  10274. }
  10275. else
  10276. {
  10277. // Fallback, extra depth only pass required
  10278. // See SSAO_DepthPass()
  10279. }
  10280. return;
  10281. }
  10282. else
  10283. {
  10284. if ( nRenderTargetID == -1 )
  10285. {
  10286. // copy depth request
  10287. // nothing to do here, extra depth pass required
  10288. return;
  10289. }
  10290. IDirect3DSurface* pRenderTargetSurface;
  10291. HRESULT hr = Dx9Device()->GetRenderTarget( nRenderTargetID, &pRenderTargetSurface );
  10292. if ( FAILED( hr ) )
  10293. {
  10294. Assert( 0 );
  10295. return;
  10296. }
  10297. IDirect3DSurface *pDstSurf;
  10298. hr = pD3DTexture->GetSurfaceLevel( 0, &pDstSurf );
  10299. Assert( !FAILED( hr ) );
  10300. if ( FAILED( hr ) )
  10301. {
  10302. pRenderTargetSurface->Release();
  10303. return;
  10304. }
  10305. bool tryblit = true;
  10306. if ( tryblit )
  10307. {
  10308. RECORD_COMMAND( DX8_COPY_FRAMEBUFFER_TO_TEXTURE, 1 );
  10309. RECORD_INT( textureHandle );
  10310. RECT srcRect, dstRect;
  10311. hr = Dx9Device()->StretchRect( pRenderTargetSurface, RectToRECT( pSrcRect, srcRect ),
  10312. pDstSurf, RectToRECT( pDstRect, dstRect ), D3DTEXF_LINEAR );
  10313. Assert( !FAILED( hr ) );
  10314. }
  10315. pDstSurf->Release();
  10316. pRenderTargetSurface->Release();
  10317. }
  10318. #elif !defined( _X360 )
  10319. static ConVarRef mat_resolveFullFrameDepth( "mat_resolveFullFrameDepth" );
  10320. if ( ( nRenderTargetID == -1 ) && g_pHardwareConfig->SupportsResolveDepth() && g_pHardwareConfig->HasFullResolutionDepthTexture() )
  10321. {
  10322. Assert( m_pZBufferSurface );
  10323. IDirect3DSurface* pDstSurf;
  10324. HRESULT hr = pD3DTexture->GetSurfaceLevel( 0, &pDstSurf );
  10325. Assert( !FAILED( hr ) );
  10326. if ( FAILED( hr ) )
  10327. {
  10328. Assert( 0 );
  10329. return;
  10330. }
  10331. bool tryblit = true;
  10332. if ( tryblit )
  10333. {
  10334. RECORD_COMMAND( DX8_COPY_FRAMEBUFFER_TO_TEXTURE, 1 );
  10335. RECORD_INT( textureHandle );
  10336. RECT srcRect, dstRect;
  10337. hr = Dx9Device()->StretchRect( m_pZBufferSurface, RectToRECT( pSrcRect, srcRect ),
  10338. pDstSurf, RectToRECT( pDstRect, dstRect ), D3DTEXF_POINT );
  10339. Assert( !FAILED( hr ) );
  10340. }
  10341. pDstSurf->Release();
  10342. }
  10343. else
  10344. {
  10345. if ( nRenderTargetID == -1 )
  10346. {
  10347. // copy depth request
  10348. // nothing to do here, extra depth pass required
  10349. return;
  10350. }
  10351. IDirect3DSurface* pRenderTargetSurface;
  10352. HRESULT hr = Dx9Device()->GetRenderTarget( nRenderTargetID, &pRenderTargetSurface );
  10353. if ( FAILED( hr ) )
  10354. {
  10355. Assert( 0 );
  10356. return;
  10357. }
  10358. IDirect3DSurface *pDstSurf;
  10359. hr = pD3DTexture->GetSurfaceLevel( 0, &pDstSurf );
  10360. Assert( !FAILED( hr ) );
  10361. if ( FAILED( hr ) )
  10362. {
  10363. pRenderTargetSurface->Release();
  10364. return;
  10365. }
  10366. bool tryblit = true;
  10367. if ( tryblit )
  10368. {
  10369. RECORD_COMMAND( DX8_COPY_FRAMEBUFFER_TO_TEXTURE, 1 );
  10370. RECORD_INT( textureHandle );
  10371. RECT srcRect, dstRect;
  10372. hr = Dx9Device()->StretchRect( pRenderTargetSurface, RectToRECT( pSrcRect, srcRect ),
  10373. pDstSurf, RectToRECT( pDstRect, dstRect ), D3DTEXF_LINEAR );
  10374. Assert( !FAILED( hr ) );
  10375. }
  10376. pDstSurf->Release();
  10377. pRenderTargetSurface->Release();
  10378. }
  10379. #else
  10380. DWORD flags = 0;
  10381. switch( nRenderTargetID )
  10382. {
  10383. case -1:
  10384. flags = D3DRESOLVE_DEPTHSTENCIL | D3DRESOLVE_FRAGMENT0;
  10385. break;
  10386. case 0:
  10387. flags = D3DRESOLVE_RENDERTARGET0;
  10388. break;
  10389. case 1:
  10390. case 2:
  10391. case 3:
  10392. // not supporting MRT
  10393. Assert( 0 );
  10394. return;
  10395. NO_DEFAULT
  10396. };
  10397. // not prepared to handle mip mapping yet
  10398. Assert( pD3DTexture->GetLevelCount() == 1 );
  10399. D3DPOINT dstPoint = { 0 };
  10400. if ( pDstRect )
  10401. {
  10402. dstPoint.x = pDstRect->x;
  10403. dstPoint.y = pDstRect->y;
  10404. }
  10405. int destWidth, destHeight;
  10406. if( pDstRect )
  10407. {
  10408. destWidth = pDstRect->width;
  10409. destHeight = pDstRect->height;
  10410. Assert( (destWidth <= pTexture->GetWidth()) && (destHeight <= pTexture->GetHeight()) );
  10411. }
  10412. else
  10413. {
  10414. destWidth = pTexture->GetWidth();
  10415. destHeight = pTexture->GetHeight();
  10416. }
  10417. RECT srcRect;
  10418. RECT *pResolveRect = NULL;
  10419. int srcWidth, srcHeight;
  10420. if ( pSrcRect )
  10421. {
  10422. RectToRECT( pSrcRect, srcRect );
  10423. pResolveRect = &srcRect;
  10424. // resolve has no stretching ability, and we can only compensate when doing a resolve to a whole texture larger than the source
  10425. Assert( !pDstRect || ( pSrcRect->width <= pDstRect->width && pSrcRect->height <= pDstRect->height ) );
  10426. srcWidth = pSrcRect->width;
  10427. srcHeight = pSrcRect->height;
  10428. }
  10429. else
  10430. {
  10431. srcRect.left = srcRect.top = 0;
  10432. srcRect.right = m_DynamicState.m_Viewport.Width;
  10433. srcRect.bottom = m_DynamicState.m_Viewport.Height;
  10434. if ( (srcRect.right < 0) || (srcRect.bottom < 0) )
  10435. {
  10436. if ( m_UsingTextureRenderTarget )
  10437. {
  10438. srcRect.right = m_ViewportMaxWidth;
  10439. srcRect.bottom = m_ViewportMaxHeight;
  10440. }
  10441. else
  10442. {
  10443. int w,h;
  10444. GetBackBufferDimensions( w, h );
  10445. srcRect.right = w;
  10446. srcRect.bottom = h;
  10447. }
  10448. }
  10449. srcWidth = srcRect.right;
  10450. srcHeight = srcRect.bottom;
  10451. }
  10452. // Save off width and height so we can restore it after the resolve
  10453. int nD3DTextureFormatSizeTwoDWidth = pD3DTexture->Format.Size.TwoD.Width;
  10454. int nD3DTextureFormatSizeTwoDHeight = pD3DTexture->Format.Size.TwoD.Height;
  10455. if ( ( srcWidth != destWidth ) || ( srcHeight != destHeight ) )
  10456. {
  10457. //Not a 1:1 resolve, we should only have gotten this far if we can downsize the target texture to compensate
  10458. Assert( (destWidth > srcWidth) && (destHeight > srcHeight) && (dstPoint.x == 0) && (dstPoint.y == 0) );
  10459. //What we're doing is telling D3D that this texture is smaller than it is so the resolve is 1:1.
  10460. //We leave the texture in this state until it resolves from something bigger.
  10461. //All outside code still thinks this texture is it's original size. And it still owns enough memory to go back to it's original size.
  10462. pD3DTexture->Format.Size.TwoD.Width = srcWidth - 1;
  10463. pD3DTexture->Format.Size.TwoD.Height = srcHeight - 1; //no idea why they store it as size-1, but they do
  10464. pResolveRect = NULL;
  10465. }
  10466. // if we convert to srgb format, we need the original format for reverting. We only need the first DWORD of GPUTEXTURE_FETCH_CONSTANT.
  10467. DWORD linearFormatBackup = pD3DTexture->Format.dword[0];
  10468. if ( !( flags & D3DRESOLVE_DEPTHSTENCIL ) && ( m_DynamicState.m_bSRGBWritesEnabled ) )
  10469. {
  10470. // we need a matched resolve regarding sRGB to get values transfered as-is
  10471. // when the surface is sRGB, use the corresponding sRGB texture
  10472. pD3DTexture->Format.SignX =
  10473. pD3DTexture->Format.SignY =
  10474. pD3DTexture->Format.SignZ = 3;
  10475. }
  10476. if ( IsDebug() )
  10477. {
  10478. // From XDK Resolve() docs...
  10479. // Each coordinate of the rectangle must be a multiple of 8 (use GPU_RESOLVE_ALIGNMENT).
  10480. // The alignment requirement is relaxed for the lower right coordinate under one conditionif,
  10481. // in conjunction with pDestPoint, it results in a destination rectangle whose lower right corner matches
  10482. // the lower right corner of the destination.
  10483. if ( pResolveRect )
  10484. {
  10485. bool bUnaligned = false;
  10486. if ( ( pResolveRect->left % GPU_RESOLVE_ALIGNMENT ) ||
  10487. ( pResolveRect->right % GPU_RESOLVE_ALIGNMENT ) ||
  10488. ( pResolveRect->top % GPU_RESOLVE_ALIGNMENT ) ||
  10489. ( pResolveRect->bottom % GPU_RESOLVE_ALIGNMENT ) )
  10490. {
  10491. bUnaligned = true;
  10492. }
  10493. if ( ( abs( pResolveRect->left - dstPoint.x ) % 32 ) ||
  10494. ( abs( pResolveRect->top - dstPoint.y ) % 32 ) )
  10495. {
  10496. bUnaligned = true;
  10497. }
  10498. if ( bUnaligned )
  10499. {
  10500. // allowed if resolve is a 1:1
  10501. if ( ( pResolveRect->left == 0 ) &&
  10502. ( pResolveRect->top == 0 ) &&
  10503. ( dstPoint.x == 0 ) &&
  10504. ( dstPoint.y == 0 ) &&
  10505. ( (unsigned int)pResolveRect->right - 1 == pD3DTexture->Format.Size.TwoD.Width ) &&
  10506. ( (unsigned int)pResolveRect->bottom - 1 == pD3DTexture->Format.Size.TwoD.Height ) )
  10507. {
  10508. bUnaligned = false;
  10509. }
  10510. }
  10511. Assert( bUnaligned == false );
  10512. }
  10513. }
  10514. #if defined( DBGFLAG_ASSERT )
  10515. if( pResolveRect )
  10516. {
  10517. D3DVIEWPORT9 viewPort;
  10518. Dx9Device()->GetViewport( &viewPort );
  10519. Assert( ( int ) viewPort.Width >= (pResolveRect->right - pResolveRect->left) ); //easier to catch here than with the cryptic error from d3d
  10520. }
  10521. #endif
  10522. HRESULT hr = Dx9Device()->Resolve( flags, (D3DRECT*)pResolveRect, pD3DTexture, &dstPoint, 0, 0, NULL, 0, 0, NULL );
  10523. Assert( !FAILED( hr ) );
  10524. pD3DTexture->Format.dword[0] = linearFormatBackup;
  10525. // Restore D3D texture to full size in case it was downsized above
  10526. pD3DTexture->Format.Size.TwoD.Width = nD3DTextureFormatSizeTwoDWidth;
  10527. pD3DTexture->Format.Size.TwoD.Height = nD3DTextureFormatSizeTwoDHeight;
  10528. #endif
  10529. }
  10530. void CShaderAPIDx8::CopyRenderTargetToTexture( ShaderAPITextureHandle_t textureHandle )
  10531. {
  10532. LOCK_SHADERAPI();
  10533. CopyRenderTargetToTextureEx( textureHandle, 0 );
  10534. }
  10535. void CShaderAPIDx8::CopyTextureToRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t textureHandle, Rect_t *pSrcRect, Rect_t *pDstRect )
  10536. {
  10537. LOCK_SHADERAPI();
  10538. VPROF( "CShaderAPIDx8::CopyRenderTargetToTexture" );
  10539. if ( !TextureIsAllocated( textureHandle ) )
  10540. return;
  10541. // Don't flush here!! If you have to flush here, then there is a driver bug.
  10542. // FlushHardware( );
  10543. AssertValidTextureHandle( textureHandle );
  10544. Texture_t *pTexture = &GetTexture( textureHandle );
  10545. Assert( pTexture );
  10546. IDirect3DTexture *pD3DTexture = (IDirect3DTexture *)pTexture->GetTexture();
  10547. Assert( pD3DTexture );
  10548. #if !defined( _X360 )
  10549. IDirect3DSurface* pRenderTargetSurface;
  10550. HRESULT hr = Dx9Device()->GetRenderTarget( nRenderTargetID, &pRenderTargetSurface );
  10551. if ( FAILED( hr ) )
  10552. {
  10553. Assert( 0 );
  10554. return;
  10555. }
  10556. IDirect3DSurface *pDstSurf;
  10557. hr = pD3DTexture->GetSurfaceLevel( 0, &pDstSurf );
  10558. Assert( !FAILED( hr ) );
  10559. if ( FAILED( hr ) )
  10560. {
  10561. pRenderTargetSurface->Release();
  10562. return;
  10563. }
  10564. bool tryblit = true;
  10565. if ( tryblit )
  10566. {
  10567. RECORD_COMMAND( DX8_COPY_FRAMEBUFFER_TO_TEXTURE, 1 );
  10568. RECORD_INT( textureHandle );
  10569. RECT srcRect, dstRect;
  10570. hr = Dx9Device()->StretchRect( pDstSurf, RectToRECT( pSrcRect, srcRect ),
  10571. pRenderTargetSurface, RectToRECT( pDstRect, dstRect ), D3DTEXF_LINEAR );
  10572. Assert( !FAILED( hr ) );
  10573. }
  10574. pDstSurf->Release();
  10575. pRenderTargetSurface->Release();
  10576. #else
  10577. Assert( 0 );
  10578. #endif
  10579. }
  10580. static const char *TextureArgToString( int arg )
  10581. {
  10582. static char buf[128];
  10583. switch( arg & D3DTA_SELECTMASK )
  10584. {
  10585. case D3DTA_DIFFUSE:
  10586. strcpy( buf, "D3DTA_DIFFUSE" );
  10587. break;
  10588. case D3DTA_CURRENT:
  10589. strcpy( buf, "D3DTA_CURRENT" );
  10590. break;
  10591. case D3DTA_TEXTURE:
  10592. strcpy( buf, "D3DTA_TEXTURE" );
  10593. break;
  10594. case D3DTA_TFACTOR:
  10595. strcpy( buf, "D3DTA_TFACTOR" );
  10596. break;
  10597. case D3DTA_SPECULAR:
  10598. strcpy( buf, "D3DTA_SPECULAR" );
  10599. break;
  10600. case D3DTA_TEMP:
  10601. strcpy( buf, "D3DTA_TEMP" );
  10602. break;
  10603. default:
  10604. strcpy( buf, "<ERROR>" );
  10605. break;
  10606. }
  10607. if( arg & D3DTA_COMPLEMENT )
  10608. {
  10609. strcat( buf, "|D3DTA_COMPLEMENT" );
  10610. }
  10611. if( arg & D3DTA_ALPHAREPLICATE )
  10612. {
  10613. strcat( buf, "|D3DTA_ALPHAREPLICATE" );
  10614. }
  10615. return buf;
  10616. }
  10617. static const char *TextureOpToString( D3DTEXTUREOP op )
  10618. {
  10619. switch( op )
  10620. {
  10621. case D3DTOP_DISABLE:
  10622. return "D3DTOP_DISABLE";
  10623. case D3DTOP_SELECTARG1:
  10624. return "D3DTOP_SELECTARG1";
  10625. case D3DTOP_SELECTARG2:
  10626. return "D3DTOP_SELECTARG2";
  10627. case D3DTOP_MODULATE:
  10628. return "D3DTOP_MODULATE";
  10629. case D3DTOP_MODULATE2X:
  10630. return "D3DTOP_MODULATE2X";
  10631. case D3DTOP_MODULATE4X:
  10632. return "D3DTOP_MODULATE4X";
  10633. case D3DTOP_ADD:
  10634. return "D3DTOP_ADD";
  10635. case D3DTOP_ADDSIGNED:
  10636. return "D3DTOP_ADDSIGNED";
  10637. case D3DTOP_ADDSIGNED2X:
  10638. return "D3DTOP_ADDSIGNED2X";
  10639. case D3DTOP_SUBTRACT:
  10640. return "D3DTOP_SUBTRACT";
  10641. case D3DTOP_ADDSMOOTH:
  10642. return "D3DTOP_ADDSMOOTH";
  10643. case D3DTOP_BLENDDIFFUSEALPHA:
  10644. return "D3DTOP_BLENDDIFFUSEALPHA";
  10645. case D3DTOP_BLENDTEXTUREALPHA:
  10646. return "D3DTOP_BLENDTEXTUREALPHA";
  10647. case D3DTOP_BLENDFACTORALPHA:
  10648. return "D3DTOP_BLENDFACTORALPHA";
  10649. case D3DTOP_BLENDTEXTUREALPHAPM:
  10650. return "D3DTOP_BLENDTEXTUREALPHAPM";
  10651. case D3DTOP_BLENDCURRENTALPHA:
  10652. return "D3DTOP_BLENDCURRENTALPHA";
  10653. case D3DTOP_PREMODULATE:
  10654. return "D3DTOP_PREMODULATE";
  10655. case D3DTOP_MODULATEALPHA_ADDCOLOR:
  10656. return "D3DTOP_MODULATEALPHA_ADDCOLOR";
  10657. case D3DTOP_MODULATECOLOR_ADDALPHA:
  10658. return "D3DTOP_MODULATECOLOR_ADDALPHA";
  10659. case D3DTOP_MODULATEINVALPHA_ADDCOLOR:
  10660. return "D3DTOP_MODULATEINVALPHA_ADDCOLOR";
  10661. case D3DTOP_MODULATEINVCOLOR_ADDALPHA:
  10662. return "D3DTOP_MODULATEINVCOLOR_ADDALPHA";
  10663. case D3DTOP_BUMPENVMAP:
  10664. return "D3DTOP_BUMPENVMAP";
  10665. case D3DTOP_BUMPENVMAPLUMINANCE:
  10666. return "D3DTOP_BUMPENVMAPLUMINANCE";
  10667. case D3DTOP_DOTPRODUCT3:
  10668. return "D3DTOP_DOTPRODUCT3";
  10669. case D3DTOP_MULTIPLYADD:
  10670. return "D3DTOP_MULTIPLYADD";
  10671. case D3DTOP_LERP:
  10672. return "D3DTOP_LERP";
  10673. default:
  10674. return "<ERROR>";
  10675. }
  10676. }
  10677. static const char *BlendModeToString( int blendMode )
  10678. {
  10679. switch( blendMode )
  10680. {
  10681. case D3DBLEND_ZERO:
  10682. return "D3DBLEND_ZERO";
  10683. case D3DBLEND_ONE:
  10684. return "D3DBLEND_ONE";
  10685. case D3DBLEND_SRCCOLOR:
  10686. return "D3DBLEND_SRCCOLOR";
  10687. case D3DBLEND_INVSRCCOLOR:
  10688. return "D3DBLEND_INVSRCCOLOR";
  10689. case D3DBLEND_SRCALPHA:
  10690. return "D3DBLEND_SRCALPHA";
  10691. case D3DBLEND_INVSRCALPHA:
  10692. return "D3DBLEND_INVSRCALPHA";
  10693. case D3DBLEND_DESTALPHA:
  10694. return "D3DBLEND_DESTALPHA";
  10695. case D3DBLEND_INVDESTALPHA:
  10696. return "D3DBLEND_INVDESTALPHA";
  10697. case D3DBLEND_DESTCOLOR:
  10698. return "D3DBLEND_DESTCOLOR";
  10699. case D3DBLEND_INVDESTCOLOR:
  10700. return "D3DBLEND_INVDESTCOLOR";
  10701. case D3DBLEND_SRCALPHASAT:
  10702. return "D3DBLEND_SRCALPHASAT";
  10703. #if !defined( _X360 )
  10704. case D3DBLEND_BOTHSRCALPHA:
  10705. return "D3DBLEND_BOTHSRCALPHA";
  10706. case D3DBLEND_BOTHINVSRCALPHA:
  10707. return "D3DBLEND_BOTHINVSRCALPHA";
  10708. #endif
  10709. default:
  10710. return "<ERROR>";
  10711. }
  10712. }
  10713. //-----------------------------------------------------------------------------
  10714. // Spew Board State
  10715. //-----------------------------------------------------------------------------
  10716. void CShaderAPIDx8::SpewBoardState()
  10717. {
  10718. // FIXME: This has regressed
  10719. return;
  10720. #ifdef DEBUG_BOARD_STATE
  10721. /*
  10722. {
  10723. static ID3DXFont* pFont = 0;
  10724. if (!pFont)
  10725. {
  10726. HFONT hFont = CreateFont( 0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
  10727. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
  10728. DEFAULT_PITCH | FF_MODERN, 0 );
  10729. Assert( hFont != 0 );
  10730. HRESULT hr = D3DXCreateFont( Dx9Device(), hFont, &pFont );
  10731. }
  10732. static char buf[1024];
  10733. static RECT r = { 0, 0, 640, 480 };
  10734. if (m_DynamicState.m_VertexBlend == 0)
  10735. return;
  10736. #if 1
  10737. D3DXMATRIX* m = &GetTransform(MATERIAL_MODEL);
  10738. D3DXMATRIX* m2 = &GetTransform(MATERIAL_MODEL + 1);
  10739. sprintf(buf,"FVF %x\n"
  10740. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10741. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n",
  10742. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n",
  10743. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n",
  10744. ShaderManager()->GetCurrentVertexShader(),
  10745. m->m[0][0], m->m[0][1], m->m[0][2], m->m[0][3],
  10746. m->m[1][0], m->m[1][1], m->m[1][2], m->m[1][3],
  10747. m->m[2][0], m->m[2][1], m->m[2][2], m->m[2][3],
  10748. m->m[3][0], m->m[3][1], m->m[3][2], m->m[3][3],
  10749. m2->m[0][0], m2->m[0][1], m2->m[0][2], m2->m[0][3],
  10750. m2->m[1][0], m2->m[1][1], m2->m[1][2], m2->m[1][3],
  10751. m2->m[2][0], m2->m[2][1], m2->m[2][2], m2->m[2][3],
  10752. m2->m[3][0], m2->m[3][1], m2->m[3][2], m2->m[3][3]
  10753. );
  10754. #else
  10755. Vector4D *pVec2 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_MODELVIEWPROJ];
  10756. Vector4D *pVec3 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_VIEWPROJ];
  10757. Vector4D *pVec4 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_MODEL];
  10758. sprintf(buf,"\n"
  10759. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10760. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
  10761. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10762. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
  10763. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10764. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
  10765. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10766. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n",
  10767. pVec1[0][0], pVec1[0][1], pVec1[0][2], pVec1[0][3],
  10768. pVec1[1][0], pVec1[1][1], pVec1[1][2], pVec1[1][3],
  10769. pVec1[2][0], pVec1[2][1], pVec1[2][2], pVec1[2][3],
  10770. pVec1[3][0], pVec1[3][1], pVec1[3][2], pVec1[3][3],
  10771. pVec2[0][0], pVec2[0][1], pVec2[0][2], pVec2[0][3],
  10772. pVec2[1][0], pVec2[1][1], pVec2[1][2], pVec2[1][3],
  10773. pVec2[2][0], pVec2[2][1], pVec2[2][2], pVec2[2][3],
  10774. pVec2[3][0], pVec2[3][1], pVec2[3][2], pVec2[3][3],
  10775. pVec3[0][0], pVec3[0][1], pVec3[0][2], pVec3[0][3],
  10776. pVec3[1][0], pVec3[1][1], pVec3[1][2], pVec3[1][3],
  10777. pVec3[2][0], pVec3[2][1], pVec3[2][2], pVec3[2][3],
  10778. pVec3[3][0], pVec3[3][1], pVec3[3][2], pVec3[3][3],
  10779. pVec4[0][0], pVec4[0][1], pVec4[0][2], pVec4[0][3],
  10780. pVec4[1][0], pVec4[1][1], pVec4[1][2], pVec4[1][3],
  10781. pVec4[2][0], pVec4[2][1], pVec4[2][2], pVec4[2][3],
  10782. 0, 0, 0, 1
  10783. );
  10784. #endif
  10785. pFont->Begin();
  10786. pFont->DrawText( buf, -1, &r, DT_LEFT | DT_TOP,
  10787. D3DCOLOR_RGBA( 255, 255, 255, 255 ) );
  10788. pFont->End();
  10789. return;
  10790. }
  10791. #if 0
  10792. Vector4D *pVec2 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_MODELVIEWPROJ];
  10793. Vector4D *pVec3 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_VIEWPROJ];
  10794. Vector4D *pVec4 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_MODEL];
  10795. static char buf2[1024];
  10796. sprintf(buf2,"\n"
  10797. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10798. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
  10799. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10800. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
  10801. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10802. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
  10803. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
  10804. "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n",
  10805. pVec1[0][0], pVec1[0][1], pVec1[0][2], pVec1[0][3],
  10806. pVec1[1][0], pVec1[1][1], pVec1[1][2], pVec1[1][3],
  10807. pVec1[2][0], pVec1[2][1], pVec1[2][2], pVec1[2][3],
  10808. pVec1[3][0], pVec1[3][1], pVec1[3][2], pVec1[3][3],
  10809. pVec2[0][0], pVec2[0][1], pVec2[0][2], pVec2[0][3],
  10810. pVec2[1][0], pVec2[1][1], pVec2[1][2], pVec2[1][3],
  10811. pVec2[2][0], pVec2[2][1], pVec2[2][2], pVec2[2][3],
  10812. pVec2[3][0], pVec2[3][1], pVec2[3][2], pVec2[3][3],
  10813. pVec3[0][0], pVec3[0][1], pVec3[0][2], pVec3[0][3],
  10814. pVec3[1][0], pVec3[1][1], pVec3[1][2], pVec3[1][3],
  10815. pVec3[2][0], pVec3[2][1], pVec3[2][2], pVec3[2][3],
  10816. pVec3[3][0], pVec3[3][1], pVec3[3][2], pVec3[3][3],
  10817. pVec4[0][0], pVec4[0][1], pVec4[0][2], pVec4[0][3],
  10818. pVec4[1][0], pVec4[1][1], pVec4[1][2], pVec4[1][3],
  10819. pVec4[2][0], pVec4[2][1], pVec4[2][2], pVec4[2][3],
  10820. 0, 0, 0, 1.0f
  10821. );
  10822. Plat_DebugString(buf2);
  10823. return;
  10824. #endif
  10825. */
  10826. char buf[256];
  10827. sprintf(buf, "\nSnapshot id %d : \n", m_TransitionTable.CurrentSnapshot() );
  10828. Plat_DebugString(buf);
  10829. ShadowState_t &boardState = m_TransitionTable.BoardState();
  10830. ShadowShaderState_t &boardShaderState = m_TransitionTable.BoardShaderState();
  10831. sprintf(buf,"Depth States: ZFunc %d, ZWrite %d, ZEnable %d, ZBias %d\n",
  10832. boardState.m_DepthTestState.m_ZFunc, boardState.m_DepthTestState.m_ZWriteEnable,
  10833. boardState.m_DepthTestState.m_ZEnable, boardState.m_DepthTestState.m_ZBias );
  10834. Plat_DebugString(buf);
  10835. sprintf(buf,"Cull Enable %d Cull Mode %d Color Write %d Fill %d Const Color sRGBWriteEnable %d\n",
  10836. boardState.m_AlphaTestAndMiscState.m_CullEnable, m_DynamicState.m_CullMode, boardState.m_DepthTestState.m_ColorWriteEnable,
  10837. boardState.m_AlphaTestAndMiscState.m_FillMode, boardState.m_FogAndMiscState.m_SRGBWriteEnable );
  10838. Plat_DebugString(buf);
  10839. AlphaBlendState_t const &boardAlpha = boardState.m_AlphaBlendState;
  10840. sprintf(buf,"Blend States: Blend Enable %d Test Enable %d Func %d SrcBlend %d (%s) DstBlend %d (%s)\n",
  10841. boardAlpha.m_AlphaBlendEnable, boardState.m_AlphaTestAndMiscState.m_AlphaTestEnable,
  10842. boardState.m_AlphaTestAndMiscState.m_AlphaFunc, boardAlpha.m_SrcBlend, BlendModeToString( boardAlpha.m_SrcBlend ),
  10843. boardAlpha.m_DestBlend, BlendModeToString( boardAlpha.m_DestBlend ) );
  10844. Plat_DebugString(buf);
  10845. int len = sprintf(buf,"Alpha Ref %d, LightsEnabled %d\n",
  10846. boardState.m_AlphaTestAndMiscState.m_AlphaRef, m_DynamicState.m_LightingState.m_nLocalLightCount );
  10847. Plat_DebugString(buf);
  10848. sprintf(buf,"Pass Vertex Usage: %llx Pixel Shader %p Vertex Shader %p\n",
  10849. boardShaderState.m_VertexUsage, ShaderManager()->GetCurrentPixelShader(),
  10850. ShaderManager()->GetCurrentVertexShader() );
  10851. Plat_DebugString(buf);
  10852. // REGRESSED!!!!
  10853. /*
  10854. D3DXMATRIX* m = &GetTransform(MATERIAL_MODEL);
  10855. sprintf(buf,"WorldMat [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
  10856. m->m[0][0], m->m[0][1], m->m[0][2], m->m[0][3],
  10857. m->m[1][0], m->m[1][1], m->m[1][2], m->m[1][3],
  10858. m->m[2][0], m->m[2][1], m->m[2][2], m->m[2][3],
  10859. m->m[3][0], m->m[3][1], m->m[3][2], m->m[3][3] );
  10860. Plat_DebugString(buf);
  10861. m = &GetTransform(MATERIAL_MODEL + 1);
  10862. sprintf(buf,"WorldMat2 [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
  10863. m->m[0][0], m->m[0][1], m->m[0][2], m->m[0][3],
  10864. m->m[1][0], m->m[1][1], m->m[1][2], m->m[1][3],
  10865. m->m[2][0], m->m[2][1], m->m[2][2], m->m[2][3],
  10866. m->m[3][0], m->m[3][1], m->m[3][2], m->m[3][3] );
  10867. Plat_DebugString(buf);
  10868. m = &GetTransform(MATERIAL_VIEW);
  10869. sprintf(buf,"ViewMat [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
  10870. m->m[0][0], m->m[0][1], m->m[0][2],
  10871. m->m[1][0], m->m[1][1], m->m[1][2],
  10872. m->m[2][0], m->m[2][1], m->m[2][2],
  10873. m->m[3][0], m->m[3][1], m->m[3][2] );
  10874. Plat_DebugString(buf);
  10875. m = &GetTransform(MATERIAL_PROJECTION);
  10876. sprintf(buf,"ProjMat [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
  10877. m->m[0][0], m->m[0][1], m->m[0][2],
  10878. m->m[1][0], m->m[1][1], m->m[1][2],
  10879. m->m[2][0], m->m[2][1], m->m[2][2],
  10880. m->m[3][0], m->m[3][1], m->m[3][2] );
  10881. Plat_DebugString(buf);
  10882. for (i = 0; i < GetTextureStageCount(); ++i)
  10883. {
  10884. m = &GetTransform(MATERIAL_TEXTURE0 + i);
  10885. sprintf(buf,"TexMat%d [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
  10886. i, m->m[0][0], m->m[0][1], m->m[0][2],
  10887. m->m[1][0], m->m[1][1], m->m[1][2],
  10888. m->m[2][0], m->m[2][1], m->m[2][2],
  10889. m->m[3][0], m->m[3][1], m->m[3][2] );
  10890. Plat_DebugString(buf);
  10891. }
  10892. */
  10893. sprintf(buf,"Viewport (%d %d) [%d %d] %4.3f %4.3f\n",
  10894. m_DynamicState.m_Viewport.X, m_DynamicState.m_Viewport.Y,
  10895. m_DynamicState.m_Viewport.Width, m_DynamicState.m_Viewport.Height,
  10896. m_DynamicState.m_Viewport.MinZ, m_DynamicState.m_Viewport.MaxZ);
  10897. Plat_DebugString(buf);
  10898. for ( int i = 0; i < MAX_SAMPLERS; ++i )
  10899. {
  10900. sprintf(buf," Texture Enabled: %d Bound Texture: %d UWrap: %d VWrap: %d\n",
  10901. SamplerState(i).m_TextureEnable, GetBoundTextureBindId( (Sampler_t)i ),
  10902. SamplerState(i).m_UTexWrap, SamplerState(i).m_VTexWrap );
  10903. Plat_DebugString(buf);
  10904. sprintf(buf," Mag Filter: %d Min Filter: %d Mip Filter: %d\n",
  10905. SamplerState(i).m_MagFilter, SamplerState(i).m_MinFilter,
  10906. SamplerState(i).m_MipFilter );
  10907. Plat_DebugString(buf);
  10908. }
  10909. #else
  10910. Plat_DebugString("::SpewBoardState() Not Implemented Yet");
  10911. #endif
  10912. }
  10913. //-----------------------------------------------------------------------------
  10914. // Begin a render pass
  10915. //-----------------------------------------------------------------------------
  10916. void CShaderAPIDx8::BeginPass( StateSnapshot_t snapshot )
  10917. {
  10918. LOCK_SHADERAPI();
  10919. VPROF("CShaderAPIDx8::BeginPass");
  10920. if (IsDeactivated())
  10921. return;
  10922. m_nCurrentSnapshot = snapshot;
  10923. // Assert( m_pRenderMesh );
  10924. // FIXME: This only does anything with temp meshes, so don't bother yet for the new code.
  10925. if( m_pRenderMesh )
  10926. {
  10927. m_pRenderMesh->BeginPass( );
  10928. }
  10929. }
  10930. //-----------------------------------------------------------------------------
  10931. // Render da polygon!
  10932. //-----------------------------------------------------------------------------
  10933. void CShaderAPIDx8::RenderPass( const unsigned char *pInstanceCommandBuffer, int nPass, int nPassCount )
  10934. {
  10935. if ( IsDeactivated() )
  10936. return;
  10937. Assert( m_nCurrentSnapshot != -1 );
  10938. // Assert( m_pRenderMesh ); MESHFIXME
  10939. m_TransitionTable.UseSnapshot( m_nCurrentSnapshot );
  10940. CommitPerPassStateChanges( m_nCurrentSnapshot );
  10941. // Make sure that we bound a texture for every stage that is enabled
  10942. // NOTE: not enabled/finished yet... see comment in CShaderAPIDx8::ApplyTextureEnable
  10943. // int nSampler;
  10944. // for ( nSampler = 0; nSampler < g_pHardwareConfig->GetSamplerCount(); nSampler++ )
  10945. // {
  10946. // if ( SamplerState( nSampler ).m_TextureEnable )
  10947. // {
  10948. // }
  10949. // }
  10950. #ifdef DEBUG_BOARD_STATE
  10951. // Spew out render state...
  10952. if ( m_pMaterial->PerformDebugTrace() )
  10953. {
  10954. SpewBoardState();
  10955. }
  10956. #endif
  10957. #ifdef TEST_CACHE_LOCKS
  10958. g_pDataCache->Flush();
  10959. #endif
  10960. // Assert( m_pRenderMesh ); MESHFIXME
  10961. if ( m_pRenderMesh )
  10962. {
  10963. m_pRenderMesh->RenderPass( pInstanceCommandBuffer );
  10964. }
  10965. else
  10966. {
  10967. MeshMgr()->RenderPassWithVertexAndIndexBuffers( pInstanceCommandBuffer );
  10968. }
  10969. m_nCurrentSnapshot = -1;
  10970. }
  10971. //-----------------------------------------------------------------------------
  10972. // Matrix mode
  10973. //-----------------------------------------------------------------------------
  10974. void CShaderAPIDx8::MatrixMode( MaterialMatrixMode_t matrixMode )
  10975. {
  10976. // NOTE!!!!!!
  10977. // The only time that m_MatrixMode is used is for texture matrices. Do not use
  10978. // it for anything else unless you change this code!
  10979. m_MatrixMode = (D3DTRANSFORMSTATETYPE)-1;
  10980. m_CurrStack = GetMatrixStack( matrixMode );
  10981. }
  10982. // The current camera position in world space.
  10983. void CShaderAPIDx8::GetWorldSpaceCameraPosition( float* pPos ) const
  10984. {
  10985. memcpy( pPos, m_WorldSpaceCameraPosition.Base(), sizeof( float[3] ) );
  10986. }
  10987. // The current camera direction in world space.
  10988. void CShaderAPIDx8::GetWorldSpaceCameraDirection( float* pPos ) const
  10989. {
  10990. memcpy( pPos, m_WorldSpaceCameraDirection.Base(), sizeof( float[3] ) );
  10991. }
  10992. void CShaderAPIDx8::CacheWorldSpaceCamera()
  10993. {
  10994. D3DXMATRIX& view = GetTransform( MATERIAL_VIEW );
  10995. m_WorldSpaceCameraPosition[0] =
  10996. -( view( 3, 0 ) * view( 0, 0 ) +
  10997. view( 3, 1 ) * view( 0, 1 ) +
  10998. view( 3, 2 ) * view( 0, 2 ) );
  10999. m_WorldSpaceCameraPosition[1] =
  11000. -( view( 3, 0 ) * view( 1, 0 ) +
  11001. view( 3, 1 ) * view( 1, 1 ) +
  11002. view( 3, 2 ) * view( 1, 2 ) );
  11003. m_WorldSpaceCameraPosition[2] =
  11004. -( view( 3, 0 ) * view( 2, 0 ) +
  11005. view( 3, 1 ) * view( 2, 1 ) +
  11006. view( 3, 2 ) * view( 2, 2 ) );
  11007. // Protect against zero, as some pixel shaders will divide by this in CalcWaterFogAlpha() in common_ps_fxc.h
  11008. if ( fabs( m_WorldSpaceCameraPosition[2] ) <= 0.00001f )
  11009. {
  11010. m_WorldSpaceCameraPosition[2] = 0.01f;
  11011. }
  11012. m_WorldSpaceCameraDirection.Init( -view(0,2), -view(1,2), -view(2, 2) );
  11013. }
  11014. //-----------------------------------------------------------------------------
  11015. // Computes a matrix which includes the poly offset given an initial projection matrix
  11016. //-----------------------------------------------------------------------------
  11017. void CShaderAPIDx8::ComputePolyOffsetMatrix( const D3DXMATRIX& matProjection, D3DXMATRIX &matProjectionOffset )
  11018. {
  11019. // We never need to do this on hardware that can handle zbias
  11020. if ( g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported )
  11021. return;
  11022. float offsetVal =
  11023. -1.0f * (m_DesiredState.m_Viewport.MaxZ - m_DesiredState.m_Viewport.MinZ) /
  11024. 16384.0f;
  11025. D3DXMATRIX offset;
  11026. D3DXMatrixTranslation( &offset, 0.0f, 0.0f, offsetVal );
  11027. D3DXMatrixMultiply( &matProjectionOffset, &matProjection, &offset );
  11028. }
  11029. //-----------------------------------------------------------------------------
  11030. // Caches off the poly-offset projection matrix
  11031. //-----------------------------------------------------------------------------
  11032. void CShaderAPIDx8::CachePolyOffsetProjectionMatrix()
  11033. {
  11034. ComputePolyOffsetMatrix( GetTransform(MATERIAL_PROJECTION), m_CachedPolyOffsetProjectionMatrix );
  11035. }
  11036. //-----------------------------------------------------------------------------
  11037. // Performs a flush on the matrix state if necessary
  11038. //-----------------------------------------------------------------------------
  11039. bool CShaderAPIDx8::MatrixIsChanging( TransformType_t type )
  11040. {
  11041. if ( IsDeactivated() )
  11042. return false;
  11043. // early out if the transform is already one of our standard types
  11044. if ((type != TRANSFORM_IS_GENERAL) && (type == m_DynamicState.m_TransformType[m_CurrStack]))
  11045. return false;
  11046. return true;
  11047. }
  11048. //-----------------------------------------------------------------------------
  11049. // Sets the actual matrix state
  11050. //-----------------------------------------------------------------------------
  11051. void CShaderAPIDx8::UpdateMatrixTransform( TransformType_t type )
  11052. {
  11053. m_DynamicState.m_TransformType[m_CurrStack] = type;
  11054. m_DynamicState.m_TransformChanged[m_CurrStack] = STATE_CHANGED;
  11055. #ifdef _DEBUG
  11056. // Store off the board state
  11057. D3DXMATRIX *pSrc = &GetTransform(m_CurrStack);
  11058. D3DXMATRIX *pDst = &m_DynamicState.m_Transform[m_CurrStack];
  11059. // Assert( *pSrc != *pDst );
  11060. memcpy( pDst, pSrc, sizeof(D3DXMATRIX) );
  11061. #endif
  11062. if ( m_CurrStack == MATERIAL_MODEL )
  11063. {
  11064. m_DynamicState.m_InstanceInfo.m_bSetSkinConstants = false;
  11065. }
  11066. if ( m_CurrStack == MATERIAL_VIEW )
  11067. {
  11068. CacheWorldSpaceCamera();
  11069. }
  11070. if ( !IsX360() && m_CurrStack == MATERIAL_PROJECTION )
  11071. {
  11072. CachePolyOffsetProjectionMatrix();
  11073. }
  11074. // Any time the view or projection matrix changes, the user clip planes need recomputing....
  11075. // Assuming we're not overriding the user clip transform
  11076. if ( ( m_CurrStack == MATERIAL_PROJECTION ) ||
  11077. ( ( m_CurrStack == MATERIAL_VIEW ) && ( !m_DynamicState.m_bUserClipTransformOverride ) ) )
  11078. {
  11079. MarkAllUserClipPlanesDirty();
  11080. }
  11081. }
  11082. //--------------------------------------------------------------------------------
  11083. // deformations
  11084. //--------------------------------------------------------------------------------
  11085. void CShaderAPIDx8::PushDeformation( DeformationBase_t const *pDef )
  11086. {
  11087. Assert( m_pDeformationStackPtr > m_DeformationStack );
  11088. --m_pDeformationStackPtr;
  11089. m_pDeformationStackPtr->m_nDeformationType = pDef->m_eType;
  11090. switch( pDef->m_eType )
  11091. {
  11092. case DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE:
  11093. {
  11094. BoxDeformation_t const *pBox = reinterpret_cast< const BoxDeformation_t *>( pDef );
  11095. m_pDeformationStackPtr->m_nNumParameters = 16;
  11096. memcpy( m_pDeformationStackPtr->m_flDeformationParameters, &( pBox->m_SourceMins.x ), 16 * sizeof( float ) );
  11097. break;
  11098. }
  11099. break;
  11100. default:
  11101. Assert( 0 );
  11102. }
  11103. }
  11104. void CShaderAPIDx8::PopDeformation( )
  11105. {
  11106. Assert( m_pDeformationStackPtr != m_DeformationStack + DEFORMATION_STACK_DEPTH );
  11107. ++m_pDeformationStackPtr;
  11108. }
  11109. int CShaderAPIDx8::GetNumActiveDeformations( void ) const
  11110. {
  11111. return ( m_DeformationStack + DEFORMATION_STACK_DEPTH ) - m_pDeformationStackPtr;
  11112. }
  11113. bool CShaderAPIDx8::IsStereoSupported() const
  11114. {
  11115. #if defined( _GAMECONSOLE )
  11116. return false;
  11117. #else
  11118. LOCK_SHADERAPI();
  11119. return Dx9Device()->IsStereoSupported();
  11120. #endif
  11121. }
  11122. void CShaderAPIDx8::UpdateStereoTexture( ShaderAPITextureHandle_t texHandle, bool *pStereoActiveThisFrame )
  11123. {
  11124. #if defined( _GAMECONSOLE )
  11125. return;
  11126. #else
  11127. LOCK_SHADERAPI();
  11128. if ( ( texHandle == INVALID_SHADERAPI_TEXTURE_HANDLE ) || !m_Textures.IsValidIndex( texHandle ) )
  11129. {
  11130. if ( pStereoActiveThisFrame )
  11131. {
  11132. *pStereoActiveThisFrame = false;
  11133. }
  11134. m_bIsStereoActiveThisFrame = false;
  11135. return;
  11136. }
  11137. IDirect3DBaseTexture *baseTex = GetTexture( texHandle ).GetTexture();
  11138. if ( ( baseTex == NULL ) || ( baseTex->GetType() != D3DRTYPE_TEXTURE ) )
  11139. {
  11140. if ( pStereoActiveThisFrame )
  11141. {
  11142. *pStereoActiveThisFrame = false;
  11143. }
  11144. m_bIsStereoActiveThisFrame = false;
  11145. return;
  11146. }
  11147. Dx9Device()->UpdateStereoTexture( ( IDirect3DTexture9 * )baseTex, m_bQueuedDeviceLost, pStereoActiveThisFrame );
  11148. if ( pStereoActiveThisFrame )
  11149. {
  11150. m_bIsStereoActiveThisFrame = *pStereoActiveThisFrame;
  11151. }
  11152. #endif
  11153. }
  11154. // for shaders to set vertex shader constants. returns a packed state which can be used to set the dynamic combo
  11155. int CShaderAPIDx8::GetPackedDeformationInformation( int nMaskOfUnderstoodDeformations,
  11156. float *pConstantValuesOut,
  11157. int nBufferSize,
  11158. int nMaximumDeformations,
  11159. int *pDefCombosOut ) const
  11160. {
  11161. int nCombosFound = 0;
  11162. memset( pDefCombosOut, 0, sizeof( pDefCombosOut[0] ) * nMaximumDeformations );
  11163. size_t nRemainingBufferSize = nBufferSize;
  11164. for( const Deformation_t *i = m_DeformationStack + DEFORMATION_STACK_DEPTH -1; i >= m_pDeformationStackPtr; i-- )
  11165. {
  11166. int nFloatsOut = 4 * ( ( i->m_nNumParameters + 3 )>> 2 );
  11167. if (
  11168. ( ( 1 << i->m_nDeformationType ) & nMaskOfUnderstoodDeformations ) &&
  11169. ( nRemainingBufferSize >= ( nFloatsOut * sizeof( float ) ) ) )
  11170. {
  11171. memcpy( pConstantValuesOut, i->m_flDeformationParameters, nFloatsOut * sizeof( float ) );
  11172. pConstantValuesOut += nFloatsOut;
  11173. nRemainingBufferSize -= nFloatsOut * sizeof( float );
  11174. ( *pDefCombosOut++ ) = i->m_nDeformationType;
  11175. nCombosFound++;
  11176. }
  11177. }
  11178. return nCombosFound;
  11179. }
  11180. //-----------------------------------------------------------------------------
  11181. // Matrix stack operations
  11182. //-----------------------------------------------------------------------------
  11183. void CShaderAPIDx8::PushMatrix()
  11184. {
  11185. // NOTE: No matrix transform update needed here.
  11186. m_pMatrixStack[m_CurrStack]->Push();
  11187. }
  11188. void CShaderAPIDx8::PopMatrix()
  11189. {
  11190. if (MatrixIsChanging())
  11191. {
  11192. m_pMatrixStack[m_CurrStack]->Pop();
  11193. UpdateMatrixTransform();
  11194. }
  11195. else
  11196. {
  11197. // Have to pop even while deactivated, otherwise the stack will overflow and we'll crash
  11198. m_pMatrixStack[m_CurrStack]->Pop();
  11199. }
  11200. }
  11201. void CShaderAPIDx8::LoadIdentity( )
  11202. {
  11203. if (MatrixIsChanging(TRANSFORM_IS_IDENTITY))
  11204. {
  11205. m_pMatrixStack[m_CurrStack]->LoadIdentity( );
  11206. UpdateMatrixTransform( TRANSFORM_IS_IDENTITY );
  11207. }
  11208. }
  11209. void CShaderAPIDx8::LoadCameraToWorld( )
  11210. {
  11211. if (MatrixIsChanging(TRANSFORM_IS_CAMERA_TO_WORLD))
  11212. {
  11213. // could just use the transpose instead, if we know there's no scale
  11214. float det;
  11215. D3DXMATRIX inv;
  11216. D3DXMatrixInverse( &inv, &det, &GetTransform(MATERIAL_VIEW) );
  11217. // Kill translation
  11218. inv.m[3][0] = inv.m[3][1] = inv.m[3][2] = 0.0f;
  11219. m_pMatrixStack[m_CurrStack]->LoadMatrix( &inv );
  11220. UpdateMatrixTransform( TRANSFORM_IS_CAMERA_TO_WORLD );
  11221. }
  11222. }
  11223. void CShaderAPIDx8::LoadMatrix( float *m )
  11224. {
  11225. // Check for identity...
  11226. if ( (fabs(m[0] - 1.0f) < 1e-3) && (fabs(m[5] - 1.0f) < 1e-3) && (fabs(m[10] - 1.0f) < 1e-3) && (fabs(m[15] - 1.0f) < 1e-3) &&
  11227. (fabs(m[1]) < 1e-3) && (fabs(m[2]) < 1e-3) && (fabs(m[3]) < 1e-3) &&
  11228. (fabs(m[4]) < 1e-3) && (fabs(m[6]) < 1e-3) && (fabs(m[7]) < 1e-3) &&
  11229. (fabs(m[8]) < 1e-3) && (fabs(m[9]) < 1e-3) && (fabs(m[11]) < 1e-3) &&
  11230. (fabs(m[12]) < 1e-3) && (fabs(m[13]) < 1e-3) && (fabs(m[14]) < 1e-3) )
  11231. {
  11232. LoadIdentity();
  11233. return;
  11234. }
  11235. if (MatrixIsChanging())
  11236. {
  11237. m_pMatrixStack[m_CurrStack]->LoadMatrix( (D3DXMATRIX*)m );
  11238. UpdateMatrixTransform();
  11239. }
  11240. }
  11241. void CShaderAPIDx8::LoadBoneMatrix( int boneIndex, const float *m )
  11242. {
  11243. if ( IsDeactivated() )
  11244. return;
  11245. memcpy( m_boneMatrix[boneIndex].Base(), m, sizeof(float)*12 );
  11246. if ( boneIndex > m_maxBoneLoaded )
  11247. {
  11248. m_maxBoneLoaded = boneIndex;
  11249. }
  11250. if ( boneIndex == 0 )
  11251. {
  11252. MatrixMode( MATERIAL_MODEL );
  11253. VMatrix transposeMatrix;
  11254. transposeMatrix.Init( *(matrix3x4_t *)m );
  11255. MatrixTranspose( transposeMatrix, transposeMatrix );
  11256. LoadMatrix( (float*)transposeMatrix.m );
  11257. }
  11258. m_DynamicState.m_InstanceInfo.m_bSetSkinConstants = false;
  11259. }
  11260. //-----------------------------------------------------------------------------
  11261. // Commits morph target factors
  11262. //-----------------------------------------------------------------------------
  11263. static void CommitFlexWeights( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState,
  11264. DynamicState_t &currentState, bool bForce )
  11265. {
  11266. if ( IsX360() )
  11267. {
  11268. // not supporting for 360
  11269. return;
  11270. }
  11271. CommitVertexShaderConstantRange( pDevice, desiredState, currentState, bForce,
  11272. VERTEX_SHADER_FLEX_WEIGHTS, VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT );
  11273. }
  11274. void CShaderAPIDx8::SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t* pWeights )
  11275. {
  11276. if ( IsX360() )
  11277. {
  11278. // not supported for 360
  11279. return;
  11280. }
  11281. LOCK_SHADERAPI();
  11282. if ( g_pHardwareConfig->Caps().m_NumVertexShaderConstants < VERTEX_SHADER_FLEX_WEIGHTS + VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT )
  11283. return;
  11284. if ( nFirstWeight + nCount > VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT )
  11285. {
  11286. Warning( "Attempted to set too many flex weights! Max is %d\n", VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT );
  11287. nCount = VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT - nFirstWeight;
  11288. }
  11289. if ( nCount <= 0 )
  11290. return;
  11291. float *pDest = m_DesiredState.m_pVectorVertexShaderConstant[ VERTEX_SHADER_FLEX_WEIGHTS + nFirstWeight ].Base();
  11292. memcpy( pDest, pWeights, nCount * sizeof(MorphWeight_t) );
  11293. ADD_COMMIT_FUNC( COMMIT_PER_DRAW, CommitFlexWeights );
  11294. }
  11295. void CShaderAPIDx8::MultMatrix( float *m )
  11296. {
  11297. if (MatrixIsChanging())
  11298. {
  11299. m_pMatrixStack[m_CurrStack]->MultMatrix( (D3DXMATRIX*)m );
  11300. UpdateMatrixTransform();
  11301. }
  11302. }
  11303. void CShaderAPIDx8::MultMatrixLocal( float *m )
  11304. {
  11305. if (MatrixIsChanging())
  11306. {
  11307. m_pMatrixStack[m_CurrStack]->MultMatrixLocal( (D3DXMATRIX*)m );
  11308. UpdateMatrixTransform();
  11309. }
  11310. }
  11311. void CShaderAPIDx8::Rotate( float angle, float x, float y, float z )
  11312. {
  11313. if (MatrixIsChanging())
  11314. {
  11315. D3DXVECTOR3 axis( x, y, z );
  11316. m_pMatrixStack[m_CurrStack]->RotateAxisLocal( &axis, M_PI * angle / 180.0f );
  11317. UpdateMatrixTransform();
  11318. }
  11319. }
  11320. void CShaderAPIDx8::Translate( float x, float y, float z )
  11321. {
  11322. if (MatrixIsChanging())
  11323. {
  11324. m_pMatrixStack[m_CurrStack]->TranslateLocal( x, y, z );
  11325. UpdateMatrixTransform();
  11326. }
  11327. }
  11328. void CShaderAPIDx8::Scale( float x, float y, float z )
  11329. {
  11330. if (MatrixIsChanging())
  11331. {
  11332. m_pMatrixStack[m_CurrStack]->ScaleLocal( x, y, z );
  11333. UpdateMatrixTransform();
  11334. }
  11335. }
  11336. void CShaderAPIDx8::ScaleXY( float x, float y )
  11337. {
  11338. if (MatrixIsChanging())
  11339. {
  11340. m_pMatrixStack[m_CurrStack]->ScaleLocal( x, y, 1.0f );
  11341. UpdateMatrixTransform();
  11342. }
  11343. }
  11344. void CShaderAPIDx8::Ortho( double left, double top, double right, double bottom, double zNear, double zFar )
  11345. {
  11346. if (MatrixIsChanging())
  11347. {
  11348. D3DXMATRIX matrix;
  11349. // FIXME: This is being used incorrectly! Should read:
  11350. // D3DXMatrixOrthoOffCenterRH( &matrix, left, right, bottom, top, zNear, zFar );
  11351. // Which is certainly why we need these extra -1 scales in y. Bleah
  11352. // NOTE: The camera can be imagined as the following diagram:
  11353. // /z
  11354. // /
  11355. // /____ x Z is going into the screen
  11356. // |
  11357. // |
  11358. // |y
  11359. //
  11360. // (0,0,z) represents the upper-left corner of the screen.
  11361. // Our projection transform needs to transform from this space to a LH coordinate
  11362. // system that looks thusly:
  11363. //
  11364. // y| /z
  11365. // | /
  11366. // |/____ x Z is going into the screen
  11367. //
  11368. // Where x,y lies between -1 and 1, and z lies from 0 to 1
  11369. // This is because the viewport transformation from projection space to pixels
  11370. // introduces a -1 scale in the y coordinates
  11371. // D3DXMatrixOrthoOffCenterLH( &matrix, left, right, bottom, top, zNear, zFar );
  11372. D3DXMatrixOrthoOffCenterRH( &matrix, left, right, top, bottom, zNear, zFar );
  11373. m_pMatrixStack[m_CurrStack]->MultMatrixLocal(&matrix);
  11374. Assert( m_CurrStack == MATERIAL_PROJECTION );
  11375. UpdateMatrixTransform();
  11376. }
  11377. }
  11378. void CShaderAPIDx8::PerspectiveX( double fovx, double aspect, double zNear, double zFar )
  11379. {
  11380. if (MatrixIsChanging())
  11381. {
  11382. float width = 2 * zNear * tan( fovx * M_PI / 360.0 );
  11383. float height = width / aspect;
  11384. Assert( m_CurrStack == MATERIAL_PROJECTION );
  11385. D3DXMATRIX rh;
  11386. D3DXMatrixPerspectiveRH( &rh, width, height, zNear, zFar );
  11387. m_pMatrixStack[m_CurrStack]->MultMatrixLocal(&rh);
  11388. UpdateMatrixTransform();
  11389. }
  11390. }
  11391. void CShaderAPIDx8::PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right )
  11392. {
  11393. if (MatrixIsChanging())
  11394. {
  11395. float width = 2 * zNear * tan( fovx * M_PI / 360.0 );
  11396. float height = width / aspect;
  11397. // bottom, top, left, right are 0..1 so convert to -1..1
  11398. float flFrontPlaneLeft = -(width/2.0f) * (1.0f - left) + left * (width/2.0f);
  11399. float flFrontPlaneRight = -(width/2.0f) * (1.0f - right) + right * (width/2.0f);
  11400. float flFrontPlaneBottom = -(height/2.0f) * (1.0f - bottom) + bottom * (height/2.0f);
  11401. float flFrontPlaneTop = -(height/2.0f) * (1.0f - top) + top * (height/2.0f);
  11402. Assert( m_CurrStack == MATERIAL_PROJECTION );
  11403. D3DXMATRIX rh;
  11404. D3DXMatrixPerspectiveOffCenterRH( &rh, flFrontPlaneLeft, flFrontPlaneRight, flFrontPlaneBottom, flFrontPlaneTop, zNear, zFar );
  11405. m_pMatrixStack[m_CurrStack]->MultMatrixLocal(&rh);
  11406. UpdateMatrixTransform();
  11407. }
  11408. }
  11409. void CShaderAPIDx8::PickMatrix( int x, int y, int width, int height )
  11410. {
  11411. if (MatrixIsChanging())
  11412. {
  11413. Assert( m_CurrStack == MATERIAL_PROJECTION );
  11414. // This is going to create a matrix to append to the standard projection.
  11415. // Projection space goes from -1 to 1 in x and y. This matrix we append
  11416. // will transform the pick region to -1 to 1 in projection space
  11417. ShaderViewport_t viewport;
  11418. GetViewports( &viewport, 1 );
  11419. int vx = viewport.m_nTopLeftX;
  11420. int vy = viewport.m_nTopLeftX;
  11421. int vwidth = viewport.m_nWidth;
  11422. int vheight = viewport.m_nHeight;
  11423. // Compute the location of the pick region in projection space...
  11424. float px = 2.0 * (float)(x - vx) / (float)vwidth - 1;
  11425. float py = 2.0 * (float)(y - vy)/ (float)vheight - 1;
  11426. float pw = 2.0 * (float)width / (float)vwidth;
  11427. float ph = 2.0 * (float)height / (float)vheight;
  11428. // we need to translate (px, py) to the origin
  11429. // and scale so (pw,ph) -> (2, 2)
  11430. D3DXMATRIX matrix;
  11431. D3DXMatrixIdentity( &matrix );
  11432. matrix.m[0][0] = 2.0 / pw;
  11433. matrix.m[1][1] = 2.0 / ph;
  11434. matrix.m[3][0] = -2.0 * px / pw;
  11435. matrix.m[3][1] = -2.0 * py / ph;
  11436. m_pMatrixStack[m_CurrStack]->MultMatrixLocal(&matrix);
  11437. UpdateMatrixTransform();
  11438. }
  11439. }
  11440. void CShaderAPIDx8::GetMatrix( MaterialMatrixMode_t matrixMode, float *dst )
  11441. {
  11442. void *pSrc = &GetTransform( matrixMode );
  11443. memcpy( (void *)dst, pSrc, sizeof(D3DXMATRIX) );
  11444. }
  11445. //-----------------------------------------------------------------------------
  11446. // Did a transform change?
  11447. //-----------------------------------------------------------------------------
  11448. inline bool CShaderAPIDx8::VertexShaderTransformChanged( int i )
  11449. {
  11450. return (m_DynamicState.m_TransformChanged[i] & STATE_CHANGED_VERTEX_SHADER) != 0;
  11451. }
  11452. const D3DXMATRIX &CShaderAPIDx8::GetProjectionMatrix( void )
  11453. {
  11454. bool bUsingZBiasProjectionMatrix =
  11455. !g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported &&
  11456. ( m_TransitionTable.CurrentSnapshot() != -1 ) &&
  11457. m_TransitionTable.CurrentShadowState() &&
  11458. m_TransitionTable.CurrentShadowState()->m_DepthTestState.m_ZBias;
  11459. if ( !m_DynamicState.m_FastClipEnabled )
  11460. {
  11461. if ( bUsingZBiasProjectionMatrix )
  11462. return m_CachedPolyOffsetProjectionMatrix;
  11463. return GetTransform( MATERIAL_PROJECTION );
  11464. }
  11465. if ( bUsingZBiasProjectionMatrix )
  11466. return m_CachedFastClipPolyOffsetProjectionMatrix;
  11467. return m_CachedFastClipProjectionMatrix;
  11468. }
  11469. //-----------------------------------------------------------------------------
  11470. // Workaround hack for visualization of selection mode
  11471. //-----------------------------------------------------------------------------
  11472. void CShaderAPIDx8::SetupSelectionModeVisualizationState()
  11473. {
  11474. Dx9Device()->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  11475. D3DXMATRIX ident;
  11476. D3DXMatrixIdentity( &ident );
  11477. SetVertexShaderConstantInternal( VERTEX_SHADER_VIEWPROJ, ident, 4 );
  11478. SetVertexShaderConstantInternal( VERTEX_SHADER_MODELVIEWPROJ, ident, 4 );
  11479. SetVertexShaderConstantInternal( VERTEX_SHADER_MODEL, ident, 3 * NUM_MODEL_TRANSFORMS );
  11480. }
  11481. //-----------------------------------------------------------------------------
  11482. // Set view transforms
  11483. //-----------------------------------------------------------------------------
  11484. static void printmat4x4( char *label, float *m00 )
  11485. {
  11486. // print label..
  11487. // fetch 4 from row, print as a row
  11488. // fetch 4 from column, print as a row
  11489. #ifdef DX_TO_GL_ABSTRACTION
  11490. float row[4];
  11491. float col[4];
  11492. GLMPRINTF(("-M- -- %s --", label ));
  11493. for( int n=0; n<4; n++ )
  11494. {
  11495. // extract row and column floats
  11496. for( int i=0; i<4;i++)
  11497. {
  11498. row[i] = m00[(n*4)+i];
  11499. col[i] = m00[(i*4)+n];
  11500. }
  11501. GLMPRINTF(( "-M- [ %7.4f %7.4f %7.4f %7.4f ] T=> [ %7.4f %7.4f %7.4f %7.4f ]",
  11502. row[0],row[1],row[2],row[3],
  11503. col[0],col[1],col[2],col[3]
  11504. ));
  11505. }
  11506. GLMPRINTF(("-M-"));
  11507. #endif
  11508. }
  11509. void CShaderAPIDx8::SetVertexShaderViewProj()
  11510. {
  11511. D3DXMATRIX transpose, matView, matProj;
  11512. matView = GetTransform(MATERIAL_VIEW);
  11513. matProj = GetProjectionMatrix();
  11514. transpose = matView * matProj;
  11515. // PS3's Cg likes things in row-major rather than column-major, so let's just save ourselves the work of fixing every shader and call it even?
  11516. #ifndef _PS3
  11517. D3DXMatrixTranspose( &transpose, &transpose );
  11518. #endif // _PS3
  11519. SetVertexShaderConstantInternal( VERTEX_SHADER_VIEWPROJ, transpose, 4 );
  11520. }
  11521. void CShaderAPIDx8::SetVertexShaderModelViewProjAndModelView( void )
  11522. {
  11523. D3DXMATRIX modelView, transpose, matView, matProj, matModel;
  11524. matModel = GetTransform(MATERIAL_MODEL);
  11525. matView = GetTransform(MATERIAL_VIEW);
  11526. matProj = GetProjectionMatrix();
  11527. D3DXMatrixMultiply( &modelView, &matModel, &matView );
  11528. D3DXMatrixMultiply( &transpose, &modelView, &matProj );
  11529. // PS3's Cg likes things in row-major rather than column-major, so let's just save ourselves the work of fixing every shader and call it even?
  11530. #ifndef _PS3
  11531. D3DXMatrixTranspose( &transpose, &transpose );
  11532. #endif // !_PS3
  11533. SetVertexShaderConstantInternal( VERTEX_SHADER_MODELVIEWPROJ, transpose, 4 );
  11534. // If we're doing FastClip, the above modelviewproj matrix won't work well for
  11535. // vertex shaders which compute projPos.z, hence we'll compute a more useful
  11536. // modelviewproj and put the third row of it in another constant
  11537. //D3DXMatrixMultiply( &transpose, &modelView, &GetTransform( MATERIAL_PROJECTION ) ); // Get the non-FastClip projection matrix
  11538. //D3DXMatrixTranspose( &transpose, &transpose );
  11539. }
  11540. void CShaderAPIDx8::UpdateVertexShaderMatrix( int iMatrix )
  11541. {
  11542. //GLM_FUNC;
  11543. if ( iMatrix == 0 )
  11544. {
  11545. int matrix = MATERIAL_MODEL;
  11546. if (VertexShaderTransformChanged(matrix))
  11547. {
  11548. int vertexShaderConstant = VERTEX_SHADER_MODEL + iMatrix * 3;
  11549. // Put the transform into the vertex shader constants...
  11550. D3DXMATRIX transpose;
  11551. D3DXMatrixTranspose( &transpose, &GetTransform(matrix) );
  11552. SetVertexShaderConstantInternal( vertexShaderConstant, transpose, 3 );
  11553. // clear the change flag
  11554. m_DynamicState.m_TransformChanged[matrix] &= ~STATE_CHANGED_VERTEX_SHADER;
  11555. }
  11556. }
  11557. else
  11558. {
  11559. SetVertexShaderConstantInternal( VERTEX_SHADER_MODEL + iMatrix, m_boneMatrix[iMatrix].Base(), 3 );
  11560. }
  11561. }
  11562. //GLM_FUNC;
  11563. //-----------------------------------------------------------------------------
  11564. // Commits vertex shader transforms that can change on a per pass basis
  11565. //-----------------------------------------------------------------------------
  11566. void CShaderAPIDx8::CommitPerPassVertexShaderTransforms()
  11567. {
  11568. //GLMPRINTF(( ">-M- CommitPerPassVertexShaderTransforms" ));
  11569. bool projChanged = VertexShaderTransformChanged( MATERIAL_PROJECTION );
  11570. if ( projChanged )
  11571. {
  11572. //GLMPRINTF(( "-M- projChanged=true in CommitPerPassVertexShaderTransforms" ));
  11573. SetVertexShaderViewProj();
  11574. SetVertexShaderModelViewProjAndModelView();
  11575. // Clear change flags
  11576. m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] &= ~STATE_CHANGED_VERTEX_SHADER;
  11577. }
  11578. else
  11579. {
  11580. //GLMPRINTF(( "-M- projChanged=false in CommitPerPassVertexShaderTransforms" ));
  11581. }
  11582. //GLMPRINTF(( "<-M- CommitPerPassVertexShaderTransforms" ));
  11583. }
  11584. //-----------------------------------------------------------------------------
  11585. // Commits vertex shader transforms
  11586. //-----------------------------------------------------------------------------
  11587. void CShaderAPIDx8::CommitVertexShaderTransforms()
  11588. {
  11589. //GLMPRINTF(( ">-M- CommitVertexShaderTransforms" ));
  11590. bool viewChanged = VertexShaderTransformChanged(MATERIAL_VIEW);
  11591. bool projChanged = VertexShaderTransformChanged(MATERIAL_PROJECTION);
  11592. bool modelChanged = VertexShaderTransformChanged(MATERIAL_MODEL) && (m_DynamicState.m_NumBones < 1);
  11593. //GLMPRINTF(( "-M- viewChanged=%s projChanged=%s modelChanged = %s in CommitVertexShaderTransforms", viewChanged?"Y":"N",projChanged?"Y":"N",modelChanged?"Y":"N" ));
  11594. if (viewChanged)
  11595. {
  11596. //GLMPRINTF(( "-M- viewChanged --> UpdateVertexShaderFogParams" ));
  11597. UpdateVertexShaderFogParams();
  11598. }
  11599. if( viewChanged || projChanged )
  11600. {
  11601. // NOTE: We have to deal with fast-clip *before*
  11602. //GLMPRINTF(( "-M- viewChanged||projChanged --> SetVertexShaderViewProj" ));
  11603. SetVertexShaderViewProj();
  11604. }
  11605. if( viewChanged || modelChanged || projChanged )
  11606. {
  11607. //GLMPRINTF(( "-M- viewChanged||projChanged||modelChanged --> SetVertexShaderModelViewProjAndModelView" ));
  11608. SetVertexShaderModelViewProjAndModelView();
  11609. }
  11610. if( modelChanged && m_DynamicState.m_NumBones < 1 )
  11611. {
  11612. UpdateVertexShaderMatrix( 0 );
  11613. }
  11614. // Clear change flags
  11615. m_DynamicState.m_TransformChanged[MATERIAL_MODEL] &= ~STATE_CHANGED_VERTEX_SHADER;
  11616. m_DynamicState.m_TransformChanged[MATERIAL_VIEW] &= ~STATE_CHANGED_VERTEX_SHADER;
  11617. m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] &= ~STATE_CHANGED_VERTEX_SHADER;
  11618. //GLMPRINTF(( "<-M- CommitVertexShaderTransforms" ));
  11619. }
  11620. bool CShaderAPIDx8::IsRenderingInstances() const
  11621. {
  11622. // Kind of hackery, but it works
  11623. return ( m_pRenderCompiledState != &m_DynamicState.m_CompiledLightingState );
  11624. }
  11625. static Vector4D s_IdentityPoseToWorld[3] =
  11626. {
  11627. Vector4D( 1, 0, 0, 0 ),
  11628. Vector4D( 0, 1, 0, 0 ),
  11629. Vector4D( 0, 0, 1, 0 )
  11630. };
  11631. bool CShaderAPIDx8::SetSkinningMatrices( const MeshInstanceData_t &instance )
  11632. {
  11633. if ( ( m_DynamicState.m_NumBones == 0 ) && !IsRenderingInstances() )
  11634. {
  11635. #if defined( DX_TO_GL_ABSTRACTION )
  11636. Dx9Device()->SetMaxUsedVertexShaderConstantsHint( VERTEX_SHADER_BONE_TRANSFORM( 0 ) + 3 );
  11637. #endif
  11638. return false;
  11639. }
  11640. // We're changing the model matrix here, we must be force the next draw call to set it
  11641. m_DynamicState.m_TransformChanged[MATERIAL_MODEL] = STATE_CHANGED;
  11642. uint nMaxVertexConstantIndex = 0;
  11643. if ( instance.m_pBoneRemap )
  11644. {
  11645. for ( int k = 0; k < instance.m_nBoneCount; ++k )
  11646. {
  11647. const int nDestBone = instance.m_pBoneRemap[k].m_nActualBoneIndex;
  11648. const int nSrcBone = instance.m_pBoneRemap[k].m_nSrcBoneIndex;
  11649. uint nIndex = VERTEX_SHADER_BONE_TRANSFORM( nDestBone );
  11650. SetVertexShaderConstantInternal( nIndex, instance.m_pPoseToWorld[ nSrcBone ].Base(), 3, true );
  11651. nMaxVertexConstantIndex = MAX( nMaxVertexConstantIndex, nIndex + 3 );
  11652. }
  11653. }
  11654. else
  11655. {
  11656. // 0 bones can come in; static prop case
  11657. if ( instance.m_pPoseToWorld )
  11658. {
  11659. int nBoneCount = MAX( 1, instance.m_nBoneCount );
  11660. uint nIndex = VERTEX_SHADER_BONE_TRANSFORM( 0 );
  11661. SetVertexShaderConstantInternal( nIndex, instance.m_pPoseToWorld[ 0 ].Base(), 3 * nBoneCount, true );
  11662. nMaxVertexConstantIndex = MAX( nMaxVertexConstantIndex, nIndex + 3 * nBoneCount );
  11663. }
  11664. else
  11665. {
  11666. uint nIndex = VERTEX_SHADER_BONE_TRANSFORM( 0 );
  11667. SetVertexShaderConstantInternal( nIndex, s_IdentityPoseToWorld[ 0 ].Base(), 3, true );
  11668. nMaxVertexConstantIndex = MAX( nMaxVertexConstantIndex, nIndex + 3 );
  11669. }
  11670. }
  11671. #if defined( DX_TO_GL_ABSTRACTION )
  11672. Dx9Device()->SetMaxUsedVertexShaderConstantsHint( nMaxVertexConstantIndex );
  11673. #endif
  11674. return true;
  11675. }
  11676. //-----------------------------------------------------------------------------
  11677. // Compiles the ambient cube lighting state
  11678. //-----------------------------------------------------------------------------
  11679. void CShaderAPIDx8::CompileAmbientCube( CompiledLightingState_t *pCompiledState, int nLightCount, const MaterialLightingState_t *pLightingState )
  11680. {
  11681. Vector4D *vecCube = pCompiledState->m_AmbientLightCube;
  11682. const Vector *pAmbient = pLightingState->m_vecAmbientCube;
  11683. vecCube[0].Init( pAmbient[0].x, pAmbient[0].y, pAmbient[0].z, 1.0f );
  11684. vecCube[1].Init( pAmbient[1].x, pAmbient[1].y, pAmbient[1].z, 1.0f );
  11685. vecCube[2].Init( pAmbient[2].x, pAmbient[2].y, pAmbient[2].z, 1.0f );
  11686. vecCube[3].Init( pAmbient[3].x, pAmbient[3].y, pAmbient[3].z, 1.0f );
  11687. vecCube[4].Init( pAmbient[4].x, pAmbient[4].y, pAmbient[4].z, 1.0f );
  11688. vecCube[5].Init( pAmbient[5].x, pAmbient[5].y, pAmbient[5].z, 1.0f );
  11689. }
  11690. //-----------------------------------------------------------------------------
  11691. // Fixes material light state so the first local light is a directional light,
  11692. // so the CSM shadow occlusion term can always be applied to the first light.
  11693. //
  11694. // Modified to be skipped for statically lit meshes (occlusion term implicitly baked into the vertex colors)
  11695. // This also allows statically lit meshes to have one extra dynamic light.
  11696. //-----------------------------------------------------------------------------
  11697. static const MaterialLightingState_t *CanonicalizeMaterialLightingStateForCSM( const MaterialLightingState_t *pOrigLightingState, MaterialLightingState_t &newLightingState, bool bStaticLight )
  11698. {
  11699. if ( !r_force_first_dynamic_light_to_directional_for_csm.GetBool() || bStaticLight )
  11700. return pOrigLightingState;
  11701. // Nothing to do if there are no local lights (the shader will be adding in no light at all, so the occlusion term can't affect anything.)
  11702. if ( ( !pOrigLightingState->m_nLocalLightCount ) || ( !g_pHardwareConfig->SupportsCascadedShadowMapping() ) )
  11703. return pOrigLightingState;
  11704. // Also nothing to do if there's >= 1 light, and the first light is a directional light.
  11705. if ( ( pOrigLightingState->m_nLocalLightCount >= 1 ) && ( pOrigLightingState->m_pLocalLightDesc[0].m_Type == MATERIAL_LIGHT_DIRECTIONAL ) )
  11706. return pOrigLightingState;
  11707. // Attempt to find a directional light in the list.
  11708. int nDirectionalLightIndex = -1;
  11709. for ( int i = 0; i < pOrigLightingState->m_nLocalLightCount; ++i)
  11710. {
  11711. if ( pOrigLightingState->m_pLocalLightDesc[i].m_Type == MATERIAL_LIGHT_DIRECTIONAL )
  11712. {
  11713. nDirectionalLightIndex = i;
  11714. break;
  11715. }
  11716. }
  11717. // Create the new material lighting state.
  11718. V_memcpy( &newLightingState, pOrigLightingState, sizeof( MaterialLightingState_t ) - MATERIAL_MAX_LIGHT_COUNT * sizeof( LightDesc_t ) );
  11719. V_memset( &newLightingState.m_pLocalLightDesc, 0, sizeof( newLightingState.m_pLocalLightDesc ) );
  11720. if ( nDirectionalLightIndex == -1 )
  11721. {
  11722. // Couldn't find a directional light, so make an all-black dummy one in the first slot.
  11723. newLightingState.m_pLocalLightDesc[0].InitDirectional( Vector( 0, 0, -1 ), Vector( 0, 0, 0 ) );
  11724. }
  11725. else
  11726. {
  11727. // Force the first slot to contain the directional light.
  11728. newLightingState.m_pLocalLightDesc[0] = pOrigLightingState->m_pLocalLightDesc[nDirectionalLightIndex];
  11729. }
  11730. // Now copy as many local lights as possible into the new material lighting state.
  11731. int nSrcLightIndex = 0;
  11732. int nDestLightIndex = 1;
  11733. while ( ( nSrcLightIndex < pOrigLightingState->m_nLocalLightCount ) && ( nDestLightIndex < MATERIAL_MAX_LIGHT_COUNT ) )
  11734. {
  11735. // Don't copy the light if its the directional light found and copied earlier.
  11736. if ( nSrcLightIndex != nDirectionalLightIndex )
  11737. {
  11738. newLightingState.m_pLocalLightDesc[nDestLightIndex] = pOrigLightingState->m_pLocalLightDesc[nSrcLightIndex];
  11739. nDestLightIndex++;
  11740. }
  11741. nSrcLightIndex++;
  11742. }
  11743. // Set the # of local lights in the new material lighting state.
  11744. newLightingState.m_nLocalLightCount = nDestLightIndex;
  11745. return &newLightingState;
  11746. }
  11747. //-----------------------------------------------------------------------------
  11748. // Generates the vertex shader constants for lights
  11749. //-----------------------------------------------------------------------------
  11750. void CShaderAPIDx8::CompileVertexShaderLocalLights( CompiledLightingState_t *pCompiledState, int nLightCount, const MaterialLightingState_t *pOrigLightingState, bool bStaticLight )
  11751. {
  11752. // For vertex shaders, we don't need to bother with the max instance lightcount
  11753. // because we use static conditionals (NOTE: test this!! might be faster to
  11754. // have lightcounts all be the same)
  11755. MaterialLightingState_t canonicalizedLightingState;
  11756. const MaterialLightingState_t *pLightingState = CanonicalizeMaterialLightingStateForCSM( pOrigLightingState, canonicalizedLightingState, bStaticLight );
  11757. // We can just use the data for this specific instance
  11758. nLightCount = MIN( pLightingState->m_nLocalLightCount, g_pHardwareConfig->MaxNumLights() );
  11759. pCompiledState->m_nLocalLightCount = nLightCount;
  11760. // Set the lighting state
  11761. for ( int i = 0; i < nLightCount; ++i )
  11762. {
  11763. Vector4D *pDest = &pCompiledState->m_VertexShaderLocalLights[ i * 5 ];
  11764. const LightDesc_t& light = pLightingState->m_pLocalLightDesc[ i ];
  11765. Assert( light.m_Type != MATERIAL_LIGHT_DISABLE );
  11766. // The first one is the light color (and light type code on DX9)
  11767. float w = ( light.m_Type == MATERIAL_LIGHT_DIRECTIONAL ) ? 1.0f : 0.0f;
  11768. pDest[0].Init( light.m_Color.x, light.m_Color.y, light.m_Color.z, w);
  11769. // The next constant holds the light direction (and light type code on DX9)
  11770. w = ( light.m_Type == MATERIAL_LIGHT_SPOT ) ? 1.0f : 0.0f;
  11771. if ( light.m_Type == MATERIAL_LIGHT_POINT )
  11772. {
  11773. pDest[1].Init( 0, 0, 0, w );
  11774. }
  11775. else
  11776. {
  11777. pDest[1].Init( light.m_Direction.x, light.m_Direction.y, light.m_Direction.z, w );
  11778. }
  11779. // The next constant holds the light position
  11780. pDest[2].Init( light.m_Position.x, light.m_Position.y, light.m_Position.z, 1.0f );
  11781. // The next constant holds exponent, stopdot, stopdot2, 1 / (stopdot - stopdot2)
  11782. if ( light.m_Type == MATERIAL_LIGHT_SPOT )
  11783. {
  11784. float oodot = light.OneOverThetaDotMinusPhiDot();
  11785. pDest[3].Init( light.m_Falloff, light.m_ThetaDot, light.m_PhiDot, oodot );
  11786. }
  11787. else
  11788. {
  11789. pDest[3].Init( 0, 1, 1, 1 );
  11790. }
  11791. // The last constant holds attenuation0, attenuation1, attenuation2
  11792. pDest[4].Init( light.m_Attenuation0, light.m_Attenuation1, light.m_Attenuation2, 0.0f );
  11793. }
  11794. // Vertex Shader loop counter for number of lights (Only the .x component is used by our shaders)
  11795. // .x is the iteration count, .y is the initial value and .z is the increment step
  11796. int *pLoopControl = pCompiledState->m_VertexShaderLocalLightLoopControl;
  11797. pLoopControl[0] = nLightCount; pLoopControl[1] = 0; pLoopControl[2] = 1; pLoopControl[3] = 0;
  11798. // Enable lights using vertex shader static flow control
  11799. int *pEnable = pCompiledState->m_VertexShaderLocalLightEnable;
  11800. for ( int i = 0; i < VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST_COUNT; ++i )
  11801. {
  11802. pEnable[i] = ( i < nLightCount ) ? 1 : 0;
  11803. }
  11804. }
  11805. //-----------------------------------------------------------------------------
  11806. // Generates the pixel shader constants for lights
  11807. //-----------------------------------------------------------------------------
  11808. void CShaderAPIDx8::CompilePixelShaderLocalLights( CompiledLightingState_t *pCompiledState, int nLightCount, const MaterialLightingState_t *pOrigLightingState, bool bStaticLight )
  11809. {
  11810. #ifndef NDEBUG
  11811. const char *materialName = m_pMaterial->GetName();
  11812. #endif
  11813. // Total pixel shader lighting state for four lights
  11814. for ( int i = 0; i < 6; i++ )
  11815. {
  11816. pCompiledState->m_PixelShaderLocalLights[i].Init();
  11817. }
  11818. if ( !pOrigLightingState )
  11819. return;
  11820. MaterialLightingState_t canonicalizedLightingState;
  11821. const MaterialLightingState_t *pLightingState = CanonicalizeMaterialLightingStateForCSM( pOrigLightingState, canonicalizedLightingState, bStaticLight );
  11822. nLightCount = pLightingState->m_nLocalLightCount;
  11823. // Offset to create a point light from directional
  11824. const float fFarAway = 10000.0f;
  11825. // NOTE: Use maxlights so we can render instances with different #s of lights
  11826. // without needing to change shader
  11827. const int nNumLights = pLightingState->m_nLocalLightCount;
  11828. int nIterCount = MIN( nLightCount, 3 );
  11829. for ( int i = 0; i < nIterCount; ++i )
  11830. {
  11831. int nIndex = 2 * i;
  11832. const LightDesc_t *light = &pLightingState->m_pLocalLightDesc[i];
  11833. Assert( light->m_Type != MATERIAL_LIGHT_DISABLE );
  11834. pCompiledState->m_PixelShaderLocalLights[nIndex].Init( light->m_Color.x, light->m_Color.y, light->m_Color.z, 0.0f );
  11835. if ( light->m_Type == MATERIAL_LIGHT_DIRECTIONAL )
  11836. {
  11837. VectorMA( pLightingState->m_vecLightingOrigin, -fFarAway, light->m_Direction, pCompiledState->m_PixelShaderLocalLights[nIndex + 1].AsVector3D() );
  11838. }
  11839. else
  11840. {
  11841. VectorCopy( light->m_Position, pCompiledState->m_PixelShaderLocalLights[nIndex + 1].AsVector3D() );
  11842. }
  11843. }
  11844. if ( nNumLights > 3 ) // At least four lights (our current max)
  11845. {
  11846. const LightDesc_t *light = &pLightingState->m_pLocalLightDesc[3];
  11847. // Spread 4th light's constants across w components
  11848. pCompiledState->m_PixelShaderLocalLights[0].w = light->m_Color.x;
  11849. pCompiledState->m_PixelShaderLocalLights[1].w = light->m_Color.y;
  11850. pCompiledState->m_PixelShaderLocalLights[2].w = light->m_Color.z;
  11851. if ( light->m_Type == MATERIAL_LIGHT_DIRECTIONAL )
  11852. {
  11853. Vector vPos;
  11854. VectorMA( pLightingState->m_vecLightingOrigin, -fFarAway, light->m_Direction, vPos );
  11855. pCompiledState->m_PixelShaderLocalLights[3].w = vPos.x;
  11856. pCompiledState->m_PixelShaderLocalLights[4].w = vPos.y;
  11857. pCompiledState->m_PixelShaderLocalLights[5].w = vPos.z;
  11858. }
  11859. else
  11860. {
  11861. pCompiledState->m_PixelShaderLocalLights[3].w = light->m_Position.x;
  11862. pCompiledState->m_PixelShaderLocalLights[4].w = light->m_Position.y;
  11863. pCompiledState->m_PixelShaderLocalLights[5].w = light->m_Position.z;
  11864. }
  11865. }
  11866. }
  11867. //-----------------------------------------------------------------------------
  11868. // Vertex Shader lighting
  11869. //-----------------------------------------------------------------------------
  11870. static float s_pTwoEmptyLights[40] = { 0,0,0,0, 1,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1, 0,0,0,0, 1,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1 };
  11871. void CShaderAPIDx8::CommitVertexShaderLighting( CompiledLightingState_t *pLightingState )
  11872. {
  11873. // Set the lighting state
  11874. if ( pLightingState->m_nLocalLightCount > 0 )
  11875. {
  11876. SetVertexShaderConstantInternal( VERTEX_SHADER_LIGHTS, pLightingState->m_VertexShaderLocalLights[0].Base(), 5 * MIN( pLightingState->m_nLocalLightCount, g_pHardwareConfig->MaxNumLights() ) );
  11877. }
  11878. // Zero out subsequent lights if we don't support static control flow
  11879. if ( ( pLightingState->m_nLocalLightCount < g_pHardwareConfig->MaxNumLights() ) && !g_pHardwareConfig->SupportsStaticControlFlow() )
  11880. {
  11881. int nLightsToSet = g_pHardwareConfig->MaxNumLights() - pLightingState->m_nLocalLightCount;
  11882. // The following logic breaks if max lights is more than two
  11883. Assert( g_pHardwareConfig->MaxNumLights() == 2 );
  11884. SetVertexShaderConstantInternal( VERTEX_SHADER_LIGHTS + 5 * (g_pHardwareConfig->MaxNumLights() - nLightsToSet), s_pTwoEmptyLights, 5 * nLightsToSet );
  11885. }
  11886. // On PS3, we don't have integer constants, so the shader code relies on the boolean flags instead
  11887. if ( !IsPS3() )
  11888. {
  11889. SetIntegerVertexShaderConstant( 0, pLightingState->m_VertexShaderLocalLightLoopControl, 1 );
  11890. }
  11891. SetBooleanVertexShaderConstant( VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST, pLightingState->m_VertexShaderLocalLightEnable, VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST_COUNT );
  11892. }
  11893. void CShaderAPIDx8::CommitPixelShaderLighting( int pshReg, CompiledLightingState_t *pLightingState )
  11894. {
  11895. if( g_pHardwareConfig->MaxNumLights() == 2 )
  11896. {
  11897. SetPixelShaderConstantInternal( pshReg, pLightingState->m_PixelShaderLocalLights[0].Base(), 4, false );
  11898. }
  11899. else
  11900. {
  11901. SetPixelShaderConstantInternal( pshReg, pLightingState->m_PixelShaderLocalLights[0].Base(), 6, false );
  11902. }
  11903. }
  11904. //-----------------------------------------------------------------------------
  11905. // Commits user clip planes
  11906. //-----------------------------------------------------------------------------
  11907. D3DXMATRIX& CShaderAPIDx8::GetUserClipTransform( )
  11908. {
  11909. if ( !m_DynamicState.m_bUserClipTransformOverride )
  11910. return GetTransform(MATERIAL_VIEW);
  11911. return m_DynamicState.m_UserClipTransform;
  11912. }
  11913. //-----------------------------------------------------------------------------
  11914. // Commits user clip planes
  11915. //-----------------------------------------------------------------------------
  11916. void CShaderAPIDx8::CommitUserClipPlanes( )
  11917. {
  11918. // We need to transform the clip planes, specified in world space,
  11919. // to be in projection space.. To transform the plane, we must transform
  11920. // the intercept and then transform the normal.
  11921. D3DXMATRIX worldToProjectionInvTrans;
  11922. #ifndef _DEBUG
  11923. if( m_DynamicState.m_UserClipPlaneChanged & m_DynamicState.m_UserClipPlaneEnabled & ((1 << g_pHardwareConfig->MaxUserClipPlanes()) - 1) )
  11924. #endif
  11925. {
  11926. worldToProjectionInvTrans = GetUserClipTransform( ) * GetTransform( MATERIAL_PROJECTION );
  11927. D3DXMatrixInverse(&worldToProjectionInvTrans, NULL, &worldToProjectionInvTrans);
  11928. // PS3's Cg likes things in row-major rather than column-major, so let's just save ourselves the work of fixing every shader and call it even?
  11929. #ifndef _PS3
  11930. D3DXMatrixTranspose(&worldToProjectionInvTrans, &worldToProjectionInvTrans);
  11931. #endif // !_PS3
  11932. }
  11933. for (int i = 0; i < g_pHardwareConfig->MaxUserClipPlanes(); ++i)
  11934. {
  11935. // Don't bother with the plane if it's not enabled
  11936. if ( (m_DynamicState.m_UserClipPlaneEnabled & (1 << i)) == 0 )
  11937. continue;
  11938. // Don't bother if it didn't change...
  11939. if ( (m_DynamicState.m_UserClipPlaneChanged & (1 << i)) == 0 )
  11940. {
  11941. #ifdef _DEBUG
  11942. //verify that the plane has not actually changed
  11943. D3DXPLANE clipPlaneProj;
  11944. D3DXPlaneTransform( &clipPlaneProj, &m_DynamicState.m_UserClipPlaneWorld[i], &worldToProjectionInvTrans );
  11945. Assert ( clipPlaneProj == m_DynamicState.m_UserClipPlaneProj[i] );
  11946. #endif
  11947. continue;
  11948. }
  11949. m_DynamicState.m_UserClipPlaneChanged &= ~(1 << i);
  11950. D3DXPLANE clipPlaneProj;
  11951. D3DXPlaneTransform( &clipPlaneProj, &m_DynamicState.m_UserClipPlaneWorld[i], &worldToProjectionInvTrans );
  11952. if ( clipPlaneProj != m_DynamicState.m_UserClipPlaneProj[i] )
  11953. {
  11954. Dx9Device()->SetClipPlane( i, (float*)clipPlaneProj );
  11955. m_DynamicState.m_UserClipPlaneProj[i] = clipPlaneProj;
  11956. }
  11957. }
  11958. }
  11959. //-----------------------------------------------------------------------------
  11960. // Need to handle fog mode on a per-pass basis
  11961. //-----------------------------------------------------------------------------
  11962. void CShaderAPIDx8::CommitPerPassFogMode( bool bUsingVertexAndPixelShaders )
  11963. {
  11964. if ( IsGameConsole() )
  11965. {
  11966. // FF fog not applicable on 360 / PS3
  11967. return;
  11968. }
  11969. D3DFOGMODE dxFogMode = D3DFOG_NONE;
  11970. if ( m_DynamicState.m_FogEnable )
  11971. {
  11972. dxFogMode = bUsingVertexAndPixelShaders ? D3DFOG_NONE : D3DFOG_LINEAR;
  11973. }
  11974. // Set fog mode if it's different than before.
  11975. if( m_DynamicState.m_FogMode != dxFogMode )
  11976. {
  11977. SetSupportedRenderState( D3DRS_FOGVERTEXMODE, dxFogMode );
  11978. m_DynamicState.m_FogMode = dxFogMode;
  11979. }
  11980. }
  11981. //-----------------------------------------------------------------------------
  11982. // Handle Xbox GPU/DX API fixups necessary before actual draw.
  11983. //-----------------------------------------------------------------------------
  11984. void CShaderAPIDx8::CommitPerPassXboxFixups()
  11985. {
  11986. #if defined( _X360 )
  11987. // send updated shader constants to gpu
  11988. WriteShaderConstantsToGPU();
  11989. // sRGB write state may have changed after RT set, have to re-set correct RT
  11990. SetRenderTargetInternalXbox( m_hCachedRenderTarget );
  11991. #endif
  11992. }
  11993. //-----------------------------------------------------------------------------
  11994. // These states can change between each pass
  11995. //-----------------------------------------------------------------------------
  11996. void CShaderAPIDx8::CommitPerPassStateChanges( StateSnapshot_t id )
  11997. {
  11998. CommitPerPassVertexShaderTransforms();
  11999. CommitPerPassFogMode( true );
  12000. CommitPerPassXboxFixups();
  12001. CallCommitFuncs( COMMIT_PER_PASS, false );
  12002. }
  12003. //-----------------------------------------------------------------------------
  12004. // Commits transforms and lighting
  12005. //-----------------------------------------------------------------------------
  12006. void CShaderAPIDx8::CommitStateChanges()
  12007. {
  12008. VPROF("CShaderAPIDx8::CommitStateChanges");
  12009. CommitFastClipPlane();
  12010. CommitVertexShaderTransforms();
  12011. if ( m_DynamicState.m_UserClipPlaneEnabled )
  12012. {
  12013. CommitUserClipPlanes( );
  12014. }
  12015. CallCommitFuncs( COMMIT_PER_DRAW );
  12016. }
  12017. //-----------------------------------------------------------------------------
  12018. // Commits viewports
  12019. //-----------------------------------------------------------------------------
  12020. static void CommitSetViewports( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce )
  12021. {
  12022. bool bChanged = bForce || memcmp( &desiredState.m_Viewport, &currentState.m_Viewport, sizeof(D3DVIEWPORT9) );
  12023. // The width + height can be zero at startup sometimes.
  12024. if ( bChanged && ( desiredState.m_Viewport.Width != 0 ) && ( desiredState.m_Viewport.Height != 0 ) )
  12025. {
  12026. if ( ReverseDepthOnX360() ) //reverse depth on 360 for better perf through hierarchical z
  12027. {
  12028. D3DVIEWPORT9 reverseDepthViewport;
  12029. reverseDepthViewport = desiredState.m_Viewport;
  12030. reverseDepthViewport.MinZ = 1.0f - desiredState.m_Viewport.MinZ;
  12031. reverseDepthViewport.MaxZ = 1.0f - desiredState.m_Viewport.MaxZ;
  12032. Dx9Device()->SetViewport( &reverseDepthViewport );
  12033. }
  12034. else
  12035. {
  12036. Dx9Device()->SetViewport( &desiredState.m_Viewport );
  12037. }
  12038. memcpy( &currentState.m_Viewport, &desiredState.m_Viewport, sizeof( D3DVIEWPORT9 ) );
  12039. }
  12040. }
  12041. void CShaderAPIDx8::SetViewports( int nCount, const ShaderViewport_t* pViewports, bool setImmediately )
  12042. {
  12043. Assert( nCount == 1 && pViewports[0].m_nVersion == SHADER_VIEWPORT_VERSION );
  12044. if ( nCount != 1 )
  12045. return;
  12046. LOCK_SHADERAPI();
  12047. D3DVIEWPORT9 viewport;
  12048. viewport.X = pViewports[0].m_nTopLeftX;
  12049. viewport.Y = pViewports[0].m_nTopLeftY;
  12050. viewport.Width = pViewports[0].m_nWidth;
  12051. viewport.Height = pViewports[0].m_nHeight;
  12052. viewport.MinZ = pViewports[0].m_flMinZ;
  12053. viewport.MaxZ = pViewports[0].m_flMaxZ;
  12054. // Clamp the viewport to the current render target...
  12055. if ( !m_UsingTextureRenderTarget )
  12056. {
  12057. // Clamp to both the back buffer and the window, if it is resizing
  12058. int nMaxWidth = 0, nMaxHeight = 0;
  12059. GetBackBufferDimensions( nMaxWidth, nMaxHeight );
  12060. if ( IsPC() && m_IsResizing )
  12061. {
  12062. RECT viewRect;
  12063. #if defined(_WIN32) && !defined( DX_TO_GL_ABSTRACTION )
  12064. GetClientRect( ( HWND )m_ViewHWnd, &viewRect );
  12065. #else
  12066. toglGetClientRect( (VD3DHWND)m_ViewHWnd, &viewRect );
  12067. #endif
  12068. m_nWindowWidth = viewRect.right - viewRect.left;
  12069. m_nWindowHeight = viewRect.bottom - viewRect.top;
  12070. nMaxWidth = MIN( m_nWindowWidth, nMaxWidth );
  12071. nMaxHeight = MIN( m_nWindowHeight, nMaxHeight );
  12072. }
  12073. // Dimensions can freak out on app exit, so at least make sure the viewport is positive
  12074. if ( (viewport.Width > (unsigned int)nMaxWidth ) && (nMaxWidth > 0) )
  12075. {
  12076. viewport.Width = nMaxWidth;
  12077. }
  12078. // Dimensions can freak out on app exit, so at least make sure the viewport is positive
  12079. if ( ( viewport.Height > (unsigned int)nMaxHeight ) && (nMaxHeight > 0) )
  12080. {
  12081. viewport.Height = nMaxHeight;
  12082. }
  12083. }
  12084. else
  12085. {
  12086. if ( viewport.Width > (unsigned int)m_ViewportMaxWidth )
  12087. {
  12088. viewport.Width = m_ViewportMaxWidth;
  12089. }
  12090. if ( viewport.Height > (unsigned int)m_ViewportMaxHeight )
  12091. {
  12092. viewport.Height = m_ViewportMaxHeight;
  12093. }
  12094. }
  12095. // FIXME: Once we extract buffered primitives out, we can directly fill in desired state
  12096. // and avoid the memcmp and copy
  12097. if ( memcmp( &m_DesiredState.m_Viewport, &viewport, sizeof(D3DVIEWPORT9) ) )
  12098. {
  12099. memcpy( &m_DesiredState.m_Viewport, &viewport, sizeof(D3DVIEWPORT9) );
  12100. }
  12101. if ( setImmediately )
  12102. {
  12103. CommitSetViewports( Dx9Device(), m_DesiredState, m_DynamicState, false);
  12104. }
  12105. else
  12106. {
  12107. ADD_COMMIT_FUNC( COMMIT_PER_DRAW, CommitSetViewports );
  12108. }
  12109. }
  12110. //-----------------------------------------------------------------------------
  12111. // Gets the current viewport size
  12112. //-----------------------------------------------------------------------------
  12113. int CShaderAPIDx8::GetViewports( ShaderViewport_t* pViewports, int nMax ) const
  12114. {
  12115. if ( !pViewports || nMax == 0 )
  12116. return 1;
  12117. LOCK_SHADERAPI();
  12118. pViewports[0].m_nTopLeftX = m_DesiredState.m_Viewport.X;
  12119. pViewports[0].m_nTopLeftY = m_DesiredState.m_Viewport.Y;
  12120. pViewports[0].m_nWidth = m_DesiredState.m_Viewport.Width;
  12121. pViewports[0].m_nHeight = m_DesiredState.m_Viewport.Height;
  12122. pViewports[0].m_flMinZ = m_DesiredState.m_Viewport.MinZ;
  12123. pViewports[0].m_flMaxZ = m_DesiredState.m_Viewport.MaxZ;
  12124. return 1;
  12125. }
  12126. //-----------------------------------------------------------------------------
  12127. // Flush the hardware
  12128. //-----------------------------------------------------------------------------
  12129. void CShaderAPIDx8::FlushHardware( )
  12130. {
  12131. LOCK_SHADERAPI();
  12132. Dx9Device()->EndScene();
  12133. DiscardVertexBuffers();
  12134. Dx9Device()->BeginScene();
  12135. ForceHardwareSync();
  12136. }
  12137. //-----------------------------------------------------------------------------
  12138. // Deal with device lost (alt-tab)
  12139. //-----------------------------------------------------------------------------
  12140. void CShaderAPIDx8::HandleDeviceLost()
  12141. {
  12142. if ( IsGameConsole() )
  12143. {
  12144. return;
  12145. }
  12146. LOCK_SHADERAPI();
  12147. if ( !IsActive() )
  12148. return;
  12149. if ( !IsDeactivated() )
  12150. {
  12151. Dx9Device()->EndScene();
  12152. }
  12153. CheckDeviceLost( m_bOtherAppInitializing );
  12154. if ( !IsDeactivated() )
  12155. {
  12156. Dx9Device()->BeginScene();
  12157. }
  12158. }
  12159. //-----------------------------------------------------------------------------
  12160. // Buffer clear color
  12161. //-----------------------------------------------------------------------------
  12162. void CShaderAPIDx8::ClearColor3ub( unsigned char r, unsigned char g, unsigned char b )
  12163. {
  12164. LOCK_SHADERAPI();
  12165. float a = 255;//(r * 0.30f + g * 0.59f + b * 0.11f) / MAX_HDR_OVERBRIGHT;
  12166. // GR - need to force alpha to black for HDR
  12167. m_DynamicState.m_ClearColor = D3DCOLOR_ARGB((unsigned char)a,r,g,b);
  12168. }
  12169. void CShaderAPIDx8::ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  12170. {
  12171. LOCK_SHADERAPI();
  12172. m_DynamicState.m_ClearColor = D3DCOLOR_ARGB(a,r,g,b);
  12173. }
  12174. // Converts the clear color to be appropriate for HDR
  12175. D3DCOLOR CShaderAPIDx8::GetActualClearColor( D3DCOLOR clearColor )
  12176. {
  12177. bool bConvert = !IsX360() && m_TransitionTable.CurrentState().m_bLinearColorSpaceFrameBufferEnable;
  12178. #if defined( _X360 )
  12179. // The PC disables SRGBWrite when clearing so that the clear color won't get gamma converted
  12180. // The 360 cannot disable that state, and thus compensates for the sRGB conversion
  12181. // the desired result is the clear color written to the RT as-is
  12182. if ( clearColor & D3DCOLOR_ARGB( 0, 255, 255, 255 ) )
  12183. {
  12184. IDirect3DSurface *pRTSurface = NULL;
  12185. Dx9Device()->GetRenderTarget( 0, &pRTSurface );
  12186. if ( pRTSurface )
  12187. {
  12188. D3DSURFACE_DESC desc;
  12189. HRESULT hr = pRTSurface->GetDesc( &desc );
  12190. if ( !FAILED( hr ) && IS_D3DFORMAT_SRGB( desc.Format ) )
  12191. {
  12192. bConvert = true;
  12193. }
  12194. pRTSurface->Release();
  12195. }
  12196. }
  12197. #endif
  12198. if ( bConvert )
  12199. {
  12200. // HDRFIXME: need to make sure this works this way.
  12201. // HDRFIXME: Is there a helper function that'll do this easier?
  12202. // convert clearColor from gamma to linear since our frame buffer is linear.
  12203. Vector vecGammaColor;
  12204. vecGammaColor.x = ( 1.0f / 255.0f ) * ( ( clearColor >> 16 ) & 0xff );
  12205. vecGammaColor.y = ( 1.0f / 255.0f ) * ( ( clearColor >> 8 ) & 0xff );
  12206. vecGammaColor.z = ( 1.0f / 255.0f ) * ( clearColor & 0xff );
  12207. Vector vecLinearColor;
  12208. vecLinearColor.x = GammaToLinear( vecGammaColor.x );
  12209. vecLinearColor.y = GammaToLinear( vecGammaColor.y );
  12210. vecLinearColor.z = GammaToLinear( vecGammaColor.z );
  12211. clearColor &= D3DCOLOR_RGBA( 0, 0, 0, 255 );
  12212. clearColor |= D3DCOLOR_COLORVALUE( vecLinearColor.x, vecLinearColor.y, vecLinearColor.z, 0.0f );
  12213. }
  12214. return clearColor;
  12215. }
  12216. //-----------------------------------------------------------------------------
  12217. // Clear buffers while obeying stencil
  12218. //-----------------------------------------------------------------------------
  12219. void CShaderAPIDx8::ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth )
  12220. {
  12221. //copy the clear color bool into the clear alpha bool
  12222. ClearBuffersObeyStencilEx( bClearColor, bClearColor, bClearDepth );
  12223. }
  12224. void CShaderAPIDx8::ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth )
  12225. {
  12226. LOCK_SHADERAPI();
  12227. if ( !bClearColor && !bClearAlpha && !bClearDepth )
  12228. return;
  12229. // Before clearing can happen, user clip planes must be disabled
  12230. SetRenderState( D3DRS_CLIPPLANEENABLE, 0 );
  12231. D3DCOLOR clearColor = GetActualClearColor( m_DynamicState.m_ClearColor );
  12232. unsigned char r, g, b, a;
  12233. b = clearColor& 0xFF;
  12234. g = ( clearColor >> 8 ) & 0xFF;
  12235. r = ( clearColor >> 16 ) & 0xFF;
  12236. a = ( clearColor >> 24 ) & 0xFF;
  12237. ShaderUtil()->DrawClearBufferQuad( r, g, b, a, bClearColor, bClearAlpha, bClearDepth );
  12238. // Reset user clip plane state
  12239. SetRenderState( D3DRS_CLIPPLANEENABLE, m_DynamicState.m_UserClipPlaneEnabled );
  12240. }
  12241. //-------------------------------------------------------------------------
  12242. //Perform stencil operations to every pixel on the screen
  12243. //-------------------------------------------------------------------------
  12244. void CShaderAPIDx8::PerformFullScreenStencilOperation( void )
  12245. {
  12246. LOCK_SHADERAPI();
  12247. // We'll be drawing a large quad in altered worldspace, user clip planes must be disabled
  12248. SetRenderState( D3DRS_CLIPPLANEENABLE, 0 );
  12249. ShaderUtil()->DrawClearBufferQuad( 0, 0, 0, 0, false, false, false );
  12250. // Reset user clip plane state
  12251. SetRenderState( D3DRS_CLIPPLANEENABLE, m_DynamicState.m_UserClipPlaneEnabled );
  12252. }
  12253. //-----------------------------------------------------------------------------
  12254. // Buffer clear
  12255. //-----------------------------------------------------------------------------
  12256. void CShaderAPIDx8::ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil, int renderTargetWidth, int renderTargetHeight )
  12257. {
  12258. LOCK_SHADERAPI();
  12259. if ( ShaderUtil()->GetConfig().m_bSuppressRendering )
  12260. return;
  12261. if ( IsDeactivated() )
  12262. return;
  12263. // State changed... need to flush the dynamic buffer
  12264. CallCommitFuncs( COMMIT_PER_DRAW, true );
  12265. float depth = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? 0.0f : 1.0f;
  12266. DWORD mask = 0;
  12267. if ( bClearColor )
  12268. {
  12269. mask |= D3DCLEAR_TARGET;
  12270. }
  12271. if ( bClearDepth )
  12272. {
  12273. mask |= D3DCLEAR_ZBUFFER;
  12274. }
  12275. /*
  12276. // HACK HACK HACK
  12277. if ( bClearDepth )
  12278. {
  12279. bClearStencil = true;
  12280. }
  12281. */
  12282. ShaderStencilState_t stencilState;
  12283. if ( bClearStencil && m_bUsingStencil )
  12284. {
  12285. mask |= D3DCLEAR_STENCIL;
  12286. #if defined( _X360 )
  12287. // Clear hi stencil to 1 (for deferred shadows)
  12288. // FIXME: Add possibility to set hi stencil clear value
  12289. GetCurrentStencilState( &stencilState );
  12290. SetSupportedRenderStateForce( D3DRS_HISTENCILENABLE, FALSE );
  12291. SetSupportedRenderStateForce( D3DRS_HISTENCILWRITEENABLE, TRUE );
  12292. SetSupportedRenderStateForce( D3DRS_HISTENCILFUNC, D3DHSCMP_NOTEQUAL ); // toggle func to EQUAL to clear to 0
  12293. SetSupportedRenderStateForce( D3DRS_HISTENCILREF, 0 );
  12294. #endif
  12295. }
  12296. // Only clear the current view... right!??!
  12297. D3DRECT clear;
  12298. clear.x1 = m_DesiredState.m_Viewport.X;
  12299. clear.y1 = m_DesiredState.m_Viewport.Y;
  12300. clear.x2 = clear.x1 + m_DesiredState.m_Viewport.Width;
  12301. clear.y2 = clear.y1 + m_DesiredState.m_Viewport.Height;
  12302. // SRGBWrite is disabled when clearing so that the clear color won't get gamma converted
  12303. bool bSRGBWriteEnable = false;
  12304. if ( !IsX360() && bClearColor && m_TransitionTable.CurrentShadowState() )
  12305. {
  12306. bSRGBWriteEnable = m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_SRGBWriteEnable;
  12307. }
  12308. #if !defined( _X360 )
  12309. if ( bSRGBWriteEnable )
  12310. {
  12311. #ifndef DX_TO_GL_ABSTRACTION
  12312. Dx9Device()->SetRenderState( D3DRS_SRGBWRITEENABLE, 0 );
  12313. #endif
  12314. }
  12315. #endif
  12316. D3DCOLOR clearColor = GetActualClearColor( m_DynamicState.m_ClearColor );
  12317. if ( mask != 0 )
  12318. {
  12319. bool bRenderTargetMatchesViewport =
  12320. ( renderTargetWidth == -1 && renderTargetHeight == -1 ) ||
  12321. ( m_DesiredState.m_Viewport.Width == -1 && m_DesiredState.m_Viewport.Height == -1 ) ||
  12322. ( renderTargetWidth == ( int )m_DesiredState.m_Viewport.Width &&
  12323. renderTargetHeight == ( int )m_DesiredState.m_Viewport.Height );
  12324. if ( bRenderTargetMatchesViewport )
  12325. {
  12326. RECORD_COMMAND( DX8_CLEAR, 6 );
  12327. RECORD_INT( 0 );
  12328. RECORD_STRUCT( &clear, sizeof(clear) );
  12329. RECORD_INT( mask );
  12330. RECORD_INT( clearColor );
  12331. RECORD_FLOAT( depth );
  12332. RECORD_INT( 0 );
  12333. Dx9Device()->Clear( 0, NULL, mask, clearColor, depth, 0L );
  12334. }
  12335. else
  12336. {
  12337. RECORD_COMMAND( DX8_CLEAR, 6 );
  12338. RECORD_INT( 0 );
  12339. RECORD_STRUCT( &clear, sizeof(clear) );
  12340. RECORD_INT( mask );
  12341. RECORD_INT( clearColor );
  12342. RECORD_FLOAT( depth );
  12343. RECORD_INT( 0 );
  12344. Dx9Device()->Clear( 1, &clear, mask, clearColor, depth, 0L );
  12345. }
  12346. }
  12347. #if defined( _X360 )
  12348. if ( mask & D3DCLEAR_STENCIL )
  12349. {
  12350. // reset hi-stencil state
  12351. SetStencilStateInternal( stencilState );
  12352. }
  12353. #endif
  12354. // Restore state
  12355. if ( bSRGBWriteEnable )
  12356. {
  12357. // sRGBWriteEnable shouldn't be true if we have no shadow state. . . Assert just in case.
  12358. Assert( m_TransitionTable.CurrentShadowState() );
  12359. m_TransitionTable.ApplySRGBWriteEnable( *m_TransitionTable.CurrentShadowState() );
  12360. }
  12361. }
  12362. //-----------------------------------------------------------------------------
  12363. // Bind
  12364. //-----------------------------------------------------------------------------
  12365. void CShaderAPIDx8::BindVertexShader( VertexShaderHandle_t hVertexShader )
  12366. {
  12367. ShaderManager()->BindVertexShader( hVertexShader );
  12368. }
  12369. void CShaderAPIDx8::BindGeometryShader( GeometryShaderHandle_t hGeometryShader )
  12370. {
  12371. Assert( hGeometryShader == GEOMETRY_SHADER_HANDLE_INVALID );
  12372. }
  12373. void CShaderAPIDx8::BindPixelShader( PixelShaderHandle_t hPixelShader )
  12374. {
  12375. ShaderManager()->BindPixelShader( hPixelShader );
  12376. }
  12377. //-----------------------------------------------------------------------------
  12378. // Returns a copy of the front buffer
  12379. //-----------------------------------------------------------------------------
  12380. IDirect3DSurface* CShaderAPIDx8::GetFrontBufferImage( ImageFormat& format )
  12381. {
  12382. #if !defined( _X360 )
  12383. int w, h;
  12384. GetBackBufferDimensions( w, h );
  12385. HRESULT hr;
  12386. IDirect3DSurface *pFullScreenSurfaceBits = 0;
  12387. hr = Dx9Device()->CreateOffscreenPlainSurface( w, h,
  12388. D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pFullScreenSurfaceBits, NULL );
  12389. if (FAILED(hr))
  12390. return 0;
  12391. hr = Dx9Device()->GetFrontBufferData( 0, pFullScreenSurfaceBits );
  12392. if (FAILED(hr))
  12393. return 0;
  12394. int windowWidth, windowHeight;
  12395. GetWindowSize( windowWidth, windowHeight );
  12396. IDirect3DSurface *pSurfaceBits = 0;
  12397. hr = Dx9Device()->CreateOffscreenPlainSurface( windowWidth, windowHeight,
  12398. D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurfaceBits, NULL );
  12399. Assert( hr == D3D_OK );
  12400. POINT pnt;
  12401. pnt.x = pnt.y = 0;
  12402. #ifdef _WIN32
  12403. BOOL result = ClientToScreen( ( HWND )m_hWnd, &pnt );
  12404. #else
  12405. BOOL result = ClientToScreen( (VD3DHWND)m_hWnd, &pnt );
  12406. #endif
  12407. Assert( result );
  12408. RECT srcRect;
  12409. srcRect.left = pnt.x;
  12410. srcRect.top = pnt.y;
  12411. srcRect.right = pnt.x + windowWidth;
  12412. srcRect.bottom = pnt.y + windowHeight;
  12413. POINT dstPnt;
  12414. dstPnt.x = dstPnt.y = 0;
  12415. D3DLOCKED_RECT lockedSrcRect;
  12416. hr = pFullScreenSurfaceBits->LockRect( &lockedSrcRect, &srcRect, D3DLOCK_READONLY );
  12417. Assert( hr == D3D_OK );
  12418. D3DLOCKED_RECT lockedDstRect;
  12419. hr = pSurfaceBits->LockRect( &lockedDstRect, NULL, 0 );
  12420. Assert( hr == D3D_OK );
  12421. int i;
  12422. for( i = 0; i < windowHeight; i++ )
  12423. {
  12424. memcpy( ( unsigned char * )lockedDstRect.pBits + ( i * lockedDstRect.Pitch ),
  12425. ( unsigned char * )lockedSrcRect.pBits + ( i * lockedSrcRect.Pitch ),
  12426. windowWidth * 4 ); // hack . . what if this is a different format?
  12427. }
  12428. hr = pSurfaceBits->UnlockRect();
  12429. Assert( hr == D3D_OK );
  12430. hr = pFullScreenSurfaceBits->UnlockRect();
  12431. Assert( hr == D3D_OK );
  12432. pFullScreenSurfaceBits->Release();
  12433. format = ImageLoader::D3DFormatToImageFormat( D3DFMT_A8R8G8B8 );
  12434. return pSurfaceBits;
  12435. #else
  12436. Assert( 0 );
  12437. return NULL;
  12438. #endif
  12439. }
  12440. //-----------------------------------------------------------------------------
  12441. // Lets the shader know about the full-screen texture so it can
  12442. //-----------------------------------------------------------------------------
  12443. void CShaderAPIDx8::SetFullScreenTextureHandle( ShaderAPITextureHandle_t h )
  12444. {
  12445. LOCK_SHADERAPI();
  12446. m_hFullScreenTexture = h;
  12447. }
  12448. //-----------------------------------------------------------------------------
  12449. // Lets the shader know about the full-screen texture so it can
  12450. //-----------------------------------------------------------------------------
  12451. void CShaderAPIDx8::SetLinearToGammaConversionTextures( ShaderAPITextureHandle_t hSRGBWriteEnabledTexture, ShaderAPITextureHandle_t hIdentityTexture )
  12452. {
  12453. LOCK_SHADERAPI();
  12454. m_hLinearToGammaTableTexture = hSRGBWriteEnabledTexture;
  12455. m_hLinearToGammaTableIdentityTexture = hIdentityTexture;
  12456. }
  12457. //-----------------------------------------------------------------------------
  12458. // Returns a copy of the back buffer
  12459. //-----------------------------------------------------------------------------
  12460. IDirect3DSurface* CShaderAPIDx8::GetBackBufferImageHDR( Rect_t *pSrcRect, Rect_t *pDstRect, ImageFormat& format )
  12461. {
  12462. #if !defined( _X360 )
  12463. HRESULT hr;
  12464. IDirect3DSurface *pSurfaceBits = 0;
  12465. IDirect3DSurface *pTmpSurface = NULL;
  12466. // Get the back buffer
  12467. IDirect3DSurface* pBackBuffer;
  12468. hr = Dx9Device()->GetRenderTarget( 0, &pBackBuffer );
  12469. if (FAILED(hr))
  12470. return 0;
  12471. // Find about its size and format
  12472. D3DSURFACE_DESC desc;
  12473. D3DTEXTUREFILTERTYPE filter;
  12474. hr = pBackBuffer->GetDesc( &desc );
  12475. if (FAILED(hr))
  12476. goto CleanUp;
  12477. filter = ((pDstRect->width != pSrcRect->width) || (pDstRect->height != pSrcRect->height)) ? D3DTEXF_LINEAR : D3DTEXF_NONE;
  12478. if ( ( pDstRect->x + pDstRect->width <= SMALL_BACK_BUFFER_SURFACE_WIDTH ) &&
  12479. ( pDstRect->y + pDstRect->height <= SMALL_BACK_BUFFER_SURFACE_HEIGHT ) )
  12480. {
  12481. if (!m_pSmallBackBufferFP16TempSurface)
  12482. {
  12483. hr = Dx9Device()->CreateRenderTarget(
  12484. SMALL_BACK_BUFFER_SURFACE_WIDTH, SMALL_BACK_BUFFER_SURFACE_HEIGHT,
  12485. desc.Format, D3DMULTISAMPLE_NONE, 0, TRUE, &m_pSmallBackBufferFP16TempSurface,
  12486. NULL );
  12487. }
  12488. pTmpSurface = m_pSmallBackBufferFP16TempSurface;
  12489. pTmpSurface->AddRef();
  12490. desc.Width = SMALL_BACK_BUFFER_SURFACE_WIDTH;
  12491. desc.Height = SMALL_BACK_BUFFER_SURFACE_HEIGHT;
  12492. RECT srcRect, destRect;
  12493. RectToRECT( pSrcRect, srcRect );
  12494. RectToRECT( pDstRect, destRect );
  12495. hr = Dx9Device()->StretchRect( pBackBuffer, &srcRect, pTmpSurface, &destRect, filter );
  12496. if ( FAILED(hr) )
  12497. goto CleanUp;
  12498. }
  12499. else
  12500. {
  12501. // Normally we would only have to create a separate render target here and StretchBlt to it first
  12502. // if AA was enabled, but certain machines/drivers get reboots if we do GetRenderTargetData
  12503. // straight off the backbuffer.
  12504. hr = Dx9Device()->CreateRenderTarget( desc.Width, desc.Height, desc.Format,
  12505. D3DMULTISAMPLE_NONE, 0, TRUE, &pTmpSurface, NULL );
  12506. if ( FAILED(hr) )
  12507. goto CleanUp;
  12508. hr = Dx9Device()->StretchRect( pBackBuffer, NULL, pTmpSurface, NULL, filter );
  12509. if ( FAILED(hr) )
  12510. goto CleanUp;
  12511. }
  12512. // Create a buffer the same size and format
  12513. hr = Dx9Device()->CreateOffscreenPlainSurface( desc.Width, desc.Height,
  12514. desc.Format, D3DPOOL_SYSTEMMEM, &pSurfaceBits, NULL );
  12515. if (FAILED(hr))
  12516. goto CleanUp;
  12517. // Blit from the back buffer to our scratch buffer
  12518. hr = Dx9Device()->GetRenderTargetData( pTmpSurface ? pTmpSurface : pBackBuffer, pSurfaceBits );
  12519. if (FAILED(hr))
  12520. goto CleanUp2;
  12521. format = ImageLoader::D3DFormatToImageFormat(desc.Format);
  12522. if ( pTmpSurface )
  12523. {
  12524. pTmpSurface->Release();
  12525. }
  12526. pBackBuffer->Release();
  12527. return pSurfaceBits;
  12528. CleanUp2:
  12529. pSurfaceBits->Release();
  12530. CleanUp:
  12531. if ( pTmpSurface )
  12532. {
  12533. pTmpSurface->Release();
  12534. }
  12535. pBackBuffer->Release();
  12536. #else
  12537. Assert( 0 );
  12538. #endif
  12539. return 0;
  12540. }
  12541. //-----------------------------------------------------------------------------
  12542. // Returns a copy of the back buffer
  12543. //-----------------------------------------------------------------------------
  12544. IDirect3DSurface* CShaderAPIDx8::GetBackBufferImage( Rect_t *pSrcRect, Rect_t *pDstRect, ImageFormat& format )
  12545. {
  12546. #if defined( _PS3 )
  12547. IDirect3DSurface *pSurf = m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT];
  12548. if ( ( pSurf ) &&
  12549. ( pSrcRect->width == pDstRect->width ) && ( pSrcRect->height == pDstRect->height ) &&
  12550. ( pSrcRect->x == 0 ) && ( pSrcRect->y == 0 ) &&
  12551. ( pDstRect->x == 0 ) && ( pDstRect->y == 0 ) )
  12552. {
  12553. D3DSURFACE_DESC desc;
  12554. HRESULT hr = pSurf->GetDesc( &desc );
  12555. if ( !FAILED( hr ) )
  12556. {
  12557. format = ImageLoader::D3DFormatToImageFormat( desc.Format );
  12558. // The actual surface data on PS3 is big endian, and the caller expects little endian data, so flip the component order. (Yes this is a big hack.)
  12559. // This is the simplest/least intrusive solution to get savegame screenshots working on ps3 I could think of.
  12560. if ( format == IMAGE_FORMAT_BGRA8888 )
  12561. {
  12562. format = IMAGE_FORMAT_ARGB8888;
  12563. }
  12564. else if ( format == IMAGE_FORMAT_ARGB8888 )
  12565. {
  12566. format = IMAGE_FORMAT_BGRA8888;
  12567. }
  12568. else if ( format == IMAGE_FORMAT_RGBA8888 )
  12569. {
  12570. format = IMAGE_FORMAT_ABGR8888;
  12571. }
  12572. else if ( format == IMAGE_FORMAT_ABGR8888 )
  12573. {
  12574. format = IMAGE_FORMAT_RGBA8888;
  12575. }
  12576. else
  12577. {
  12578. AssertOnce( "Unsupported backbuffer format in GetBackBufferImage\n" );
  12579. }
  12580. pSurf->AddRef();
  12581. // For safety, wait until the GPU backend finishes writing to the backbuffer.
  12582. IDirect3DQuery9 *pQuery = NULL;
  12583. Dx9Device()->CreateQuery( D3DQUERYTYPE_EVENT, &pQuery );
  12584. if ( pQuery )
  12585. {
  12586. pQuery->Issue( D3DISSUE_END );
  12587. BOOL bQueryResult;
  12588. pQuery->GetData( &bQueryResult, sizeof( bQueryResult ), D3DGETDATA_FLUSH );
  12589. pQuery->Release();
  12590. __sync();
  12591. }
  12592. return pSurf;
  12593. }
  12594. }
  12595. return NULL;
  12596. #elif !defined( _X360 )
  12597. if ( !m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT] || ( m_hFullScreenTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) )
  12598. return NULL;
  12599. HRESULT hr;
  12600. D3DSURFACE_DESC desc;
  12601. // Get the current render target
  12602. IDirect3DSurface* pRenderTarget;
  12603. hr = Dx9Device()->GetRenderTarget( 0, &pRenderTarget );
  12604. if (FAILED(hr))
  12605. return 0;
  12606. // Find about its size and format
  12607. hr = pRenderTarget->GetDesc( &desc );
  12608. if ( desc.Format == D3DFMT_A16B16G16R16F || desc.Format == D3DFMT_A32B32G32R32F )
  12609. return GetBackBufferImageHDR( pSrcRect, pDstRect, format );
  12610. IDirect3DSurface *pSurfaceBits = NULL;
  12611. IDirect3DSurface *pTmpSurface = NULL;
  12612. int nRenderTargetRefCount;
  12613. REFERENCE( nRenderTargetRefCount );
  12614. if ( (desc.MultiSampleType == D3DMULTISAMPLE_NONE) && (pRenderTarget != m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT]) &&
  12615. (pSrcRect->width == pDstRect->width) && (pSrcRect->height == pDstRect->height) )
  12616. {
  12617. // Don't bother to blit through the full-screen texture if we don't
  12618. // have to stretch, we're not coming from the backbuffer, and we don't have to do AA resolve
  12619. pTmpSurface = pRenderTarget;
  12620. pTmpSurface->AddRef();
  12621. }
  12622. else
  12623. {
  12624. Texture_t *pTex = &GetTexture( m_hFullScreenTexture );
  12625. IDirect3DTexture* pFullScreenTexture = (IDirect3DTexture*)pTex->GetTexture();
  12626. D3DTEXTUREFILTERTYPE filter = ((pDstRect->width != pSrcRect->width) || (pDstRect->height != pSrcRect->height)) ? D3DTEXF_LINEAR : D3DTEXF_NONE;
  12627. hr = pFullScreenTexture->GetSurfaceLevel( 0, &pTmpSurface );
  12628. if ( FAILED(hr) )
  12629. goto CleanUp;
  12630. if ( pTmpSurface == pRenderTarget )
  12631. {
  12632. Warning( "Can't blit from full-sized offscreen buffer!\n" );
  12633. goto CleanUp;
  12634. }
  12635. RECT srcRect, destRect;
  12636. srcRect.left = pSrcRect->x; srcRect.right = pSrcRect->x + pSrcRect->width;
  12637. srcRect.top = pSrcRect->y; srcRect.bottom = pSrcRect->y + pSrcRect->height;
  12638. srcRect.left = clamp( srcRect.left, 0, (int)desc.Width );
  12639. srcRect.right = clamp( srcRect.right, 0, (int)desc.Width );
  12640. srcRect.top = clamp( srcRect.top, 0, (int)desc.Height );
  12641. srcRect.bottom = clamp( srcRect.bottom, 0, (int)desc.Height );
  12642. destRect.left = pDstRect->x ; destRect.right = pDstRect->x + pDstRect->width;
  12643. destRect.top = pDstRect->y; destRect.bottom = pDstRect->y + pDstRect->height;
  12644. destRect.left = clamp( destRect.left, 0, (int)desc.Width );
  12645. destRect.right = clamp( destRect.right, 0, (int)desc.Width );
  12646. destRect.top = clamp( destRect.top, 0, (int)desc.Height );
  12647. destRect.bottom = clamp( destRect.bottom, 0, (int)desc.Height );
  12648. hr = Dx9Device()->StretchRect( pRenderTarget, &srcRect, pTmpSurface, &destRect, filter );
  12649. if ( FAILED(hr) )
  12650. {
  12651. AssertOnce( "Error resizing pixels!\n" );
  12652. goto CleanUp;
  12653. }
  12654. }
  12655. D3DSURFACE_DESC tmpDesc;
  12656. hr = pTmpSurface->GetDesc( &tmpDesc );
  12657. Assert( !FAILED(hr) );
  12658. // Create a buffer the same size and format
  12659. hr = Dx9Device()->CreateOffscreenPlainSurface( tmpDesc.Width, tmpDesc.Height,
  12660. desc.Format, D3DPOOL_SYSTEMMEM, &pSurfaceBits, NULL );
  12661. if ( FAILED(hr) )
  12662. {
  12663. AssertOnce( "Error creating offscreen surface!\n" );
  12664. goto CleanUp;
  12665. }
  12666. // Blit from the back buffer to our scratch buffer
  12667. hr = Dx9Device()->GetRenderTargetData( pTmpSurface, pSurfaceBits );
  12668. if ( FAILED(hr) )
  12669. {
  12670. AssertOnce( "Error copying bits into the offscreen surface!\n" );
  12671. goto CleanUp;
  12672. }
  12673. format = ImageLoader::D3DFormatToImageFormat( desc.Format );
  12674. pTmpSurface->Release();
  12675. #ifdef _DEBUG
  12676. nRenderTargetRefCount =
  12677. #endif
  12678. pRenderTarget->Release();
  12679. Assert( nRenderTargetRefCount == 1 );
  12680. return pSurfaceBits;
  12681. CleanUp:
  12682. if ( pSurfaceBits )
  12683. {
  12684. pSurfaceBits->Release();
  12685. }
  12686. if ( pTmpSurface )
  12687. {
  12688. pTmpSurface->Release();
  12689. }
  12690. #else
  12691. Assert( 0 );
  12692. #endif
  12693. return 0;
  12694. }
  12695. //-----------------------------------------------------------------------------
  12696. // Copy bits from a host-memory surface
  12697. //-----------------------------------------------------------------------------
  12698. void CShaderAPIDx8::CopyBitsFromHostSurface( IDirect3DSurface* pSurfaceBits,
  12699. const Rect_t &dstRect, unsigned char *pData, ImageFormat srcFormat, ImageFormat dstFormat, int nDstStride )
  12700. {
  12701. // Copy out the bits...
  12702. RECT rect;
  12703. rect.left = dstRect.x;
  12704. rect.right = dstRect.x + dstRect.width;
  12705. rect.top = dstRect.y;
  12706. rect.bottom = dstRect.y + dstRect.height;
  12707. D3DLOCKED_RECT lockedRect;
  12708. HRESULT hr;
  12709. int flags = D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK;
  12710. hr = pSurfaceBits->LockRect( &lockedRect, &rect, flags );
  12711. if ( !FAILED( hr ) )
  12712. {
  12713. unsigned char *pImage = (unsigned char *)lockedRect.pBits;
  12714. ShaderUtil()->ConvertImageFormat( (unsigned char *)pImage, srcFormat,
  12715. pData, dstFormat, dstRect.width, dstRect.height, lockedRect.Pitch, nDstStride );
  12716. hr = pSurfaceBits->UnlockRect( );
  12717. }
  12718. }
  12719. //-----------------------------------------------------------------------------
  12720. // Reads from the current read buffer + stretches
  12721. //-----------------------------------------------------------------------------
  12722. void CShaderAPIDx8::ReadPixels( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *pData, ImageFormat dstFormat, int nDstStride )
  12723. {
  12724. LOCK_SHADERAPI();
  12725. Assert( pDstRect );
  12726. if ( IsPC() || !IsX360() )
  12727. {
  12728. Rect_t srcRect;
  12729. if ( !pSrcRect )
  12730. {
  12731. srcRect.x = srcRect.y = 0;
  12732. srcRect.width = m_nWindowWidth;
  12733. srcRect.height = m_nWindowHeight;
  12734. pSrcRect = &srcRect;
  12735. }
  12736. ImageFormat format;
  12737. IDirect3DSurface* pSurfaceBits = GetBackBufferImage( pSrcRect, pDstRect, format );
  12738. if ( pSurfaceBits )
  12739. {
  12740. CopyBitsFromHostSurface( pSurfaceBits, *pDstRect, pData, format, dstFormat, nDstStride );
  12741. // Release the temporary surface
  12742. pSurfaceBits->Release();
  12743. }
  12744. }
  12745. else
  12746. {
  12747. #if defined( _X360 )
  12748. // 360 requires material system to handle due to RT complexities
  12749. ShaderUtil()->ReadBackBuffer( pSrcRect, pDstRect, pData, dstFormat, nDstStride );
  12750. #endif
  12751. }
  12752. }
  12753. //-----------------------------------------------------------------------------
  12754. // Reads from the current read buffer
  12755. //-----------------------------------------------------------------------------
  12756. void CShaderAPIDx8::ReadPixels( int x, int y, int width, int height, unsigned char *pData, ImageFormat dstFormat, ITexture *pRenderTargetTexture )
  12757. {
  12758. Rect_t rect;
  12759. rect.x = x;
  12760. rect.y = y;
  12761. rect.width = width;
  12762. rect.height = height;
  12763. if ( IsPC() || !IsX360() )
  12764. {
  12765. ImageFormat format;
  12766. IDirect3DSurface* pSurfaceBits = NULL;
  12767. if ( pRenderTargetTexture != NULL )
  12768. {
  12769. format = pRenderTargetTexture->GetImageFormat();
  12770. ShaderAPITextureHandle_t hRenderTargetTexture = ShaderUtil()->GetShaderAPITextureBindHandle( pRenderTargetTexture, 0, 0 );
  12771. //render targets can't be locked, luckily we can copy the surface to system memory and lock that.
  12772. IDirect3DSurface *pSystemSurface;
  12773. IDirect3DSurface* pRTSurface = GetTextureSurface( hRenderTargetTexture );
  12774. D3DSURFACE_DESC surfaceDesc;
  12775. pRTSurface->GetDesc( &surfaceDesc );
  12776. Assert( !IsX360() );
  12777. HRESULT hr = Dx9Device()->CreateOffscreenPlainSurface( surfaceDesc.Width, surfaceDesc.Height, surfaceDesc.Format, D3DPOOL_SYSTEMMEM, &pSystemSurface, NULL );
  12778. Assert( SUCCEEDED( hr ) );
  12779. if ( pSystemSurface != NULL )
  12780. {
  12781. pSystemSurface->GetDesc( &surfaceDesc );
  12782. hr = Dx9Device()->GetRenderTargetData( pRTSurface, pSystemSurface );
  12783. Assert( SUCCEEDED( hr ) );
  12784. }
  12785. //pretend this is the texture level we originally grabbed with GetSurfaceLevel() and continue on
  12786. pRTSurface->Release();
  12787. pSurfaceBits = pSystemSurface;
  12788. }
  12789. else
  12790. {
  12791. pSurfaceBits = GetBackBufferImage( &rect, &rect, format );
  12792. }
  12793. if (pSurfaceBits)
  12794. {
  12795. CopyBitsFromHostSurface( pSurfaceBits, rect, pData, format, dstFormat, 0 );
  12796. // Release the temporary surface
  12797. pSurfaceBits->Release();
  12798. }
  12799. }
  12800. else
  12801. {
  12802. #if defined( _X360 )
  12803. // 360 requires material system to handle due to RT complexities
  12804. ShaderUtil()->ReadBackBuffer( &rect, &rect, pData, dstFormat, 0 );
  12805. #endif
  12806. }
  12807. }
  12808. static IDirect3DSurface *s_pSystemSurface = NULL;
  12809. static ImageFormat s_format;
  12810. // this is not fully async, it syncronizes the queue
  12811. // it does get queued and run from the render thread (if enabled)
  12812. void CShaderAPIDx8::ReadPixelsAsync( int x, int y, int width, int height, unsigned char *pData, ImageFormat dstFormat, ITexture *pRenderTargetTexture, CThreadEvent *pPixelsReadEvent )
  12813. {
  12814. TM_ZONE( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
  12815. Rect_t rect;
  12816. rect.x = x;
  12817. rect.y = y;
  12818. rect.width = width;
  12819. rect.height = height;
  12820. if ( IsPC() || !IsX360() )
  12821. {
  12822. if ( pRenderTargetTexture != NULL )
  12823. {
  12824. s_format = pRenderTargetTexture->GetImageFormat();
  12825. ShaderAPITextureHandle_t hRenderTargetTexture = ShaderUtil()->GetShaderAPITextureBindHandle( pRenderTargetTexture, 0, 0 );
  12826. //render targets can't be locked, luckily we can copy the surface to system memory and lock that.
  12827. if ( IDirect3DSurface* pRTSurface = GetTextureSurface( hRenderTargetTexture ) )
  12828. {
  12829. D3DSURFACE_DESC surfaceDesc;
  12830. pRTSurface->GetDesc( &surfaceDesc );
  12831. Assert( !IsX360() );
  12832. HRESULT hr = Dx9Device()->CreateOffscreenPlainSurface( surfaceDesc.Width, surfaceDesc.Height, surfaceDesc.Format, D3DPOOL_SYSTEMMEM, &s_pSystemSurface, NULL );
  12833. Assert( SUCCEEDED( hr ) );
  12834. if ( s_pSystemSurface != NULL )
  12835. {
  12836. s_pSystemSurface->GetDesc( &surfaceDesc );
  12837. hr = Dx9Device()->GetRenderTargetData( pRTSurface, s_pSystemSurface );
  12838. Assert( SUCCEEDED( hr ) );
  12839. }
  12840. //pretend this is the texture level we originally grabbed with GetSurfaceLevel() and continue on
  12841. pRTSurface->Release();
  12842. }
  12843. }
  12844. else
  12845. {
  12846. s_pSystemSurface = GetBackBufferImage( &rect, &rect, s_format );
  12847. }
  12848. }
  12849. else
  12850. {
  12851. #if defined( _X360 )
  12852. Assert( 0 ); // not supported
  12853. #endif
  12854. }
  12855. // if the caller gave us a thread event, then signal the event
  12856. if ( pPixelsReadEvent )
  12857. {
  12858. pPixelsReadEvent->Set();
  12859. }
  12860. }
  12861. void CShaderAPIDx8::ReadPixelsAsyncGetResult( int x, int y, int width, int height, unsigned char *pData, ImageFormat dstFormat, CThreadEvent *pGetResultEvent )
  12862. {
  12863. TM_ZONE( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
  12864. Rect_t rect;
  12865. rect.x = x;
  12866. rect.y = y;
  12867. rect.width = width;
  12868. rect.height = height;
  12869. if (s_pSystemSurface)
  12870. {
  12871. CopyBitsFromHostSurface( s_pSystemSurface, rect, pData, s_format, dstFormat, 0 );
  12872. // Release the temporary surface
  12873. s_pSystemSurface->Release();
  12874. }
  12875. // if the caller gave us a thread event, then signal the event
  12876. if ( pGetResultEvent )
  12877. {
  12878. pGetResultEvent->Set();
  12879. }
  12880. }
  12881. //-----------------------------------------------------------------------------
  12882. // Binds a particular material to render with
  12883. //-----------------------------------------------------------------------------
  12884. void CShaderAPIDx8::Bind( IMaterial* pMaterial )
  12885. {
  12886. LOCK_SHADERAPI();
  12887. IMaterialInternal* pMatInt = static_cast<IMaterialInternal*>( pMaterial );
  12888. bool bMaterialChanged;
  12889. if ( m_pMaterial && pMatInt && m_pMaterial->InMaterialPage() && pMatInt->InMaterialPage() )
  12890. {
  12891. bMaterialChanged = ( m_pMaterial->GetMaterialPage() != pMatInt->GetMaterialPage() );
  12892. }
  12893. else
  12894. {
  12895. bMaterialChanged = ( m_pMaterial != pMatInt ) || ( m_pMaterial && m_pMaterial->InMaterialPage() ) || ( pMatInt && pMatInt->InMaterialPage() );
  12896. }
  12897. if ( bMaterialChanged )
  12898. {
  12899. #ifdef RECORDING
  12900. RECORD_DEBUG_STRING( ( char * )pMaterial->GetName() );
  12901. IShader *pShader = pMatInt->GetShader();
  12902. if( pShader && pShader->GetName() )
  12903. {
  12904. RECORD_DEBUG_STRING( pShader->GetName() );
  12905. }
  12906. else
  12907. {
  12908. RECORD_DEBUG_STRING( "<NULL SHADER>" );
  12909. }
  12910. #endif
  12911. m_pMaterial = pMatInt;
  12912. #if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) || ( defined( PLATFORM_POSIX ) && GLMDEBUG ) )
  12913. PIXifyName( s_pPIXMaterialName, m_pMaterial->GetName() );
  12914. #endif
  12915. #ifdef _GAMECONSOLE
  12916. if ( m_bInZPass )
  12917. {
  12918. if ( pMatInt->IsAlphaTested() || pMatInt->IsTranslucent() )
  12919. {
  12920. // we need to predicate render calls with this material to only occur during main rendering and not the z pass
  12921. Dx9Device()->SetPredication( D3DPRED_ALL_RENDER );
  12922. }
  12923. else
  12924. {
  12925. Dx9Device()->SetPredication( 0 );
  12926. }
  12927. }
  12928. #endif
  12929. }
  12930. }
  12931. // Get the currently bound material
  12932. IMaterialInternal* CShaderAPIDx8::GetBoundMaterial()
  12933. {
  12934. return m_pMaterial;
  12935. }
  12936. //-----------------------------------------------------------------------------
  12937. // Binds a standard texture
  12938. //-----------------------------------------------------------------------------
  12939. #ifndef _PS3
  12940. void CShaderAPIDx8::BindStandardTexture( Sampler_t sampler, TextureBindFlags_t nBindFlags, StandardTextureId_t id )
  12941. {
  12942. if ( IsRenderingInstances() )
  12943. {
  12944. // when rendering instances, if they are binding one of the per-instance replacable std
  12945. // textures, we don't want to bind it - we just want to remember what sampler it was bound
  12946. // to so we can plug in the correct texture at the time we draw the instances.
  12947. int nMask = ( 1 << sampler );
  12948. m_DynamicState.m_nLocalEnvCubemapSamplers &= ~nMask;
  12949. m_DynamicState.m_nLightmapSamplers &= ~nMask;
  12950. m_DynamicState.m_nPaintmapSamplers &= ~nMask;
  12951. if ( id == TEXTURE_LOCAL_ENV_CUBEMAP )
  12952. {
  12953. m_DynamicState.m_nLocalEnvCubemapSamplers |= nMask;
  12954. SetLastSetTextureBindFlags( sampler, nBindFlags );
  12955. return;
  12956. }
  12957. if ( id == TEXTURE_LIGHTMAP )
  12958. {
  12959. m_DynamicState.m_nLightmapSamplers |= nMask;
  12960. SetLastSetTextureBindFlags( sampler, nBindFlags );
  12961. return;
  12962. }
  12963. if ( id == TEXTURE_PAINT )
  12964. {
  12965. m_DynamicState.m_nPaintmapSamplers |= nMask;
  12966. SetLastSetTextureBindFlags( sampler, nBindFlags );
  12967. return;
  12968. }
  12969. }
  12970. if ( m_StdTextureHandles[id] != INVALID_SHADERAPI_TEXTURE_HANDLE )
  12971. {
  12972. BindTexture( sampler, nBindFlags, m_StdTextureHandles[id] );
  12973. }
  12974. else
  12975. {
  12976. ShaderUtil()->BindStandardTexture( sampler, nBindFlags, id );
  12977. }
  12978. Assert( LastSetTextureBindFlags( sampler ) == nBindFlags );
  12979. }
  12980. #endif
  12981. void CShaderAPIDx8::BindStandardVertexTexture( VertexTextureSampler_t sampler, StandardTextureId_t id )
  12982. {
  12983. ShaderUtil()->BindStandardVertexTexture( sampler, id );
  12984. }
  12985. void CShaderAPIDx8::GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id )
  12986. {
  12987. ShaderUtil()->GetStandardTextureDimensions( pWidth, pHeight, id );
  12988. }
  12989. float CShaderAPIDx8::GetSubDHeight()
  12990. {
  12991. return ShaderUtil()->GetSubDHeight();
  12992. }
  12993. bool CShaderAPIDx8::IsStereoActiveThisFrame() const
  12994. {
  12995. return m_bIsStereoActiveThisFrame;
  12996. }
  12997. //-----------------------------------------------------------------------------
  12998. // Gets the lightmap dimensions
  12999. //-----------------------------------------------------------------------------
  13000. void CShaderAPIDx8::GetLightmapDimensions( int *w, int *h )
  13001. {
  13002. ShaderUtil()->GetLightmapDimensions( w, h );
  13003. }
  13004. //-----------------------------------------------------------------------------
  13005. // Selection mode methods
  13006. //-----------------------------------------------------------------------------
  13007. int CShaderAPIDx8::SelectionMode( bool selectionMode )
  13008. {
  13009. LOCK_SHADERAPI();
  13010. int numHits = m_NumHits;
  13011. if (m_InSelectionMode)
  13012. {
  13013. WriteHitRecord();
  13014. }
  13015. m_InSelectionMode = selectionMode;
  13016. m_pCurrSelectionRecord = m_pSelectionBuffer;
  13017. m_NumHits = 0;
  13018. return numHits;
  13019. }
  13020. bool CShaderAPIDx8::IsInSelectionMode() const
  13021. {
  13022. return m_InSelectionMode;
  13023. }
  13024. void CShaderAPIDx8::SelectionBuffer( unsigned int* pBuffer, int size )
  13025. {
  13026. LOCK_SHADERAPI();
  13027. Assert( !m_InSelectionMode );
  13028. Assert( pBuffer && size );
  13029. m_pSelectionBufferEnd = pBuffer + size;
  13030. m_pSelectionBuffer = pBuffer;
  13031. m_pCurrSelectionRecord = pBuffer;
  13032. }
  13033. void CShaderAPIDx8::ClearSelectionNames( )
  13034. {
  13035. LOCK_SHADERAPI();
  13036. if (m_InSelectionMode)
  13037. {
  13038. WriteHitRecord();
  13039. }
  13040. m_SelectionNames.Clear();
  13041. }
  13042. void CShaderAPIDx8::LoadSelectionName( int name )
  13043. {
  13044. LOCK_SHADERAPI();
  13045. if (m_InSelectionMode)
  13046. {
  13047. WriteHitRecord();
  13048. Assert( m_SelectionNames.Count() > 0 );
  13049. m_SelectionNames.Top() = name;
  13050. }
  13051. }
  13052. void CShaderAPIDx8::PushSelectionName( int name )
  13053. {
  13054. LOCK_SHADERAPI();
  13055. if (m_InSelectionMode)
  13056. {
  13057. WriteHitRecord();
  13058. m_SelectionNames.Push(name);
  13059. }
  13060. }
  13061. void CShaderAPIDx8::PopSelectionName()
  13062. {
  13063. LOCK_SHADERAPI();
  13064. if (m_InSelectionMode)
  13065. {
  13066. WriteHitRecord();
  13067. m_SelectionNames.Pop();
  13068. }
  13069. }
  13070. void CShaderAPIDx8::WriteHitRecord( )
  13071. {
  13072. if (m_SelectionNames.Count() && (m_SelectionMinZ != FLT_MAX))
  13073. {
  13074. Assert( m_pCurrSelectionRecord + m_SelectionNames.Count() + 3 < m_pSelectionBufferEnd );
  13075. *m_pCurrSelectionRecord++ = m_SelectionNames.Count();
  13076. // NOTE: because of rounding, "(uint32)(float)UINT32_MAX" yields zero(!), hence the use of doubles.
  13077. // [ ALSO: As of Nov 2011, VS2010 exhibits a debug build code-gen bug if we cast the result to int32 instead of uint32 ]
  13078. *m_pCurrSelectionRecord++ = (uint32)( 0.5 + m_SelectionMinZ*(double)((uint32)~0) );
  13079. *m_pCurrSelectionRecord++ = (uint32)( 0.5 + m_SelectionMaxZ*(double)((uint32)~0) );
  13080. for (int i = 0; i < m_SelectionNames.Count(); ++i)
  13081. {
  13082. *m_pCurrSelectionRecord++ = m_SelectionNames[i];
  13083. }
  13084. ++m_NumHits;
  13085. }
  13086. m_SelectionMinZ = FLT_MAX;
  13087. m_SelectionMaxZ = FLT_MIN;
  13088. }
  13089. // We hit something in selection mode
  13090. void CShaderAPIDx8::RegisterSelectionHit( float minz, float maxz )
  13091. {
  13092. if (minz < 0)
  13093. minz = 0;
  13094. if (maxz > 1)
  13095. maxz = 1;
  13096. if (m_SelectionMinZ > minz)
  13097. m_SelectionMinZ = minz;
  13098. if (m_SelectionMaxZ < maxz)
  13099. m_SelectionMaxZ = maxz;
  13100. }
  13101. int CShaderAPIDx8::GetCurrentNumBones( void ) const
  13102. {
  13103. return m_DynamicState.m_NumBones;
  13104. }
  13105. bool CShaderAPIDx8::IsHWMorphingEnabled( ) const
  13106. {
  13107. return m_DynamicState.m_bHWMorphingEnabled;
  13108. }
  13109. TessellationMode_t CShaderAPIDx8::GetTessellationMode( ) const
  13110. {
  13111. return m_DynamicState.m_TessellationMode;
  13112. }
  13113. static Vector s_EmptyCube[6];
  13114. void CShaderAPIDx8::RecomputeAggregateLightingState( void )
  13115. {
  13116. m_DynamicState.m_ShaderLightState.m_bAmbientLight = false;
  13117. m_DynamicState.m_ShaderLightState.m_nNumLights = 0;
  13118. m_DynamicState.m_ShaderLightState.m_bStaticLight = false;
  13119. m_DynamicState.m_ShaderLightState.m_bStaticLightIndirectOnly = false;
  13120. for ( int i = 0; i < m_nRenderInstanceCount; ++i )
  13121. {
  13122. const MaterialLightingState_t *pLightingState = m_pRenderInstances[i].m_pLightingState;
  13123. if ( !pLightingState )
  13124. continue;
  13125. if ( !m_DynamicState.m_ShaderLightState.m_bAmbientLight )
  13126. {
  13127. m_DynamicState.m_ShaderLightState.m_bAmbientLight = ( memcmp( s_EmptyCube, pLightingState->m_vecAmbientCube, 18 * sizeof(float) ) != 0 );
  13128. }
  13129. if ( !m_DynamicState.m_ShaderLightState.m_bStaticLight )
  13130. {
  13131. m_DynamicState.m_ShaderLightState.m_bStaticLight = ( m_pRenderInstances[i].m_pColorBuffer != NULL );
  13132. }
  13133. if ( !m_DynamicState.m_ShaderLightState.m_bStaticLightIndirectOnly )
  13134. {
  13135. m_DynamicState.m_ShaderLightState.m_bStaticLightIndirectOnly = m_pRenderInstances[i].m_bColorBufferHasIndirectLightingOnly;
  13136. }
  13137. #ifdef _DEBUG
  13138. if ( g_pHardwareConfig->GetDXSupportLevel() >= 92 )
  13139. {
  13140. Assert( pLightingState->m_nLocalLightCount <= MATERIAL_MAX_LIGHT_COUNT ); // 2b hardware gets four lights
  13141. }
  13142. else
  13143. {
  13144. Assert( pLightingState->m_nLocalLightCount <= (MATERIAL_MAX_LIGHT_COUNT-2) ); // 2.0 hardware gets two less
  13145. }
  13146. #endif
  13147. int nNumLights = pLightingState->m_nLocalLightCount;
  13148. // Only force the first dynamic light to directional for csm for non statically lit meshes (or those that only have indirect lighting baked, like phong static props)
  13149. if ( nNumLights &&
  13150. ( ( !m_DynamicState.m_ShaderLightState.m_bStaticLight ) || m_DynamicState.m_ShaderLightState.m_bStaticLightIndirectOnly ) &&
  13151. r_force_first_dynamic_light_to_directional_for_csm.GetBool() &&
  13152. g_pHardwareConfig->SupportsCascadedShadowMapping() )
  13153. {
  13154. int j;
  13155. for ( j = 0; j < nNumLights; ++j )
  13156. {
  13157. if ( pLightingState->m_pLocalLightDesc[j].m_Type == MATERIAL_LIGHT_DIRECTIONAL )
  13158. break;
  13159. }
  13160. if ( j == nNumLights )
  13161. {
  13162. // Bump up the # of actual lights to account for the hidden all-black directional light.
  13163. // This solution sucks, because if numlights already equals MATERIAL_MAX_LIGHT_COUNT we will be deleting the last local light.
  13164. // A better way would be to add a scalar in the compiled light state which suppresses the CSM shadows.
  13165. nNumLights = MIN( nNumLights + 1, MATERIAL_MAX_LIGHT_COUNT );
  13166. }
  13167. }
  13168. m_DynamicState.m_ShaderLightState.m_nNumLights = MAX( m_DynamicState.m_ShaderLightState.m_nNumLights, nNumLights );
  13169. // Cap it to the maximum number of lights supported by the hardware
  13170. m_DynamicState.m_ShaderLightState.m_nNumLights = MIN( m_DynamicState.m_ShaderLightState.m_nNumLights, g_pHardwareConfig->MaxNumLights() );
  13171. }
  13172. }
  13173. void CShaderAPIDx8::GetDX9LightState( LightState_t *state ) const
  13174. {
  13175. if ( !m_DynamicState.m_bLightStateComputed )
  13176. {
  13177. const_cast<CShaderAPIDx8*>(this)->RecomputeAggregateLightingState();
  13178. m_DynamicState.m_bLightStateComputed = true;
  13179. }
  13180. memcpy( state, &m_DynamicState.m_ShaderLightState, sizeof(LightState_t) );
  13181. }
  13182. MaterialFogMode_t CShaderAPIDx8::GetCurrentFogType( void ) const
  13183. {
  13184. Assert( 0 ); // deprecated. don't use
  13185. return MATERIAL_FOG_NONE;
  13186. }
  13187. void CShaderAPIDx8::RecordString( const char *pStr )
  13188. {
  13189. RECORD_STRING( pStr );
  13190. }
  13191. void CShaderAPIDx8::EvictManagedResourcesInternal()
  13192. {
  13193. if ( IsGameConsole() )
  13194. return;
  13195. if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
  13196. {
  13197. ShaderUtil()->OnThreadEvent( SHADER_THREAD_EVICT_RESOURCES );
  13198. return;
  13199. }
  13200. if ( mat_debugalttab.GetBool() )
  13201. {
  13202. Warning( "mat_debugalttab: CShaderAPIDx8::EvictManagedResourcesInternal\n" );
  13203. }
  13204. #if !defined( _X360 )
  13205. if ( Dx9Device() )
  13206. {
  13207. Dx9Device()->EvictManagedResources();
  13208. }
  13209. #endif
  13210. }
  13211. void CShaderAPIDx8::EvictManagedResources( void )
  13212. {
  13213. if ( IsGameConsole() )
  13214. {
  13215. return;
  13216. }
  13217. LOCK_SHADERAPI();
  13218. Assert(ThreadOwnsDevice());
  13219. // Tell other material system applications to release resources
  13220. SendIPCMessage( EVICT_MESSAGE );
  13221. EvictManagedResourcesInternal();
  13222. }
  13223. void CShaderAPIDx8::GetGPUMemoryStats( GPUMemoryStats &stats )
  13224. {
  13225. #ifdef _PS3
  13226. Dx9Device()->GetGPUMemoryStats( stats );
  13227. #else
  13228. // TODO: 360/PC/mac (if possible/useful)
  13229. memset( &stats, 0, sizeof( stats ) );
  13230. #endif
  13231. }
  13232. bool CShaderAPIDx8::IsDebugTextureListFresh( int numFramesAllowed /* = 1 */ )
  13233. {
  13234. return ( m_nDebugDataExportFrame <= m_CurrentFrame ) && ( m_nDebugDataExportFrame >= m_CurrentFrame - numFramesAllowed );
  13235. }
  13236. bool CShaderAPIDx8::SetDebugTextureRendering( bool bEnable )
  13237. {
  13238. bool bVal = m_bDebugTexturesRendering;
  13239. m_bDebugTexturesRendering = bEnable;
  13240. return bVal;
  13241. }
  13242. void CShaderAPIDx8::EnableDebugTextureList( bool bEnable )
  13243. {
  13244. m_bEnableDebugTextureList = bEnable;
  13245. }
  13246. void CShaderAPIDx8::EnableGetAllTextures( bool bEnable )
  13247. {
  13248. m_bDebugGetAllTextures = bEnable;
  13249. }
  13250. KeyValues* CShaderAPIDx8::LockDebugTextureList( void )
  13251. {
  13252. m_DebugTextureListLock.Lock();
  13253. return m_pDebugTextureList;
  13254. }
  13255. void CShaderAPIDx8::UnlockDebugTextureList( void )
  13256. {
  13257. m_DebugTextureListLock.Unlock();
  13258. }
  13259. int CShaderAPIDx8::GetTextureMemoryUsed( TextureMemoryType eTextureMemory )
  13260. {
  13261. switch ( eTextureMemory )
  13262. {
  13263. case MEMORY_BOUND_LAST_FRAME:
  13264. return m_nTextureMemoryUsedLastFrame;
  13265. case MEMORY_TOTAL_LOADED:
  13266. return m_nTextureMemoryUsedTotal;
  13267. case MEMORY_ESTIMATE_PICMIP_1:
  13268. return m_nTextureMemoryUsedPicMip1;
  13269. case MEMORY_ESTIMATE_PICMIP_2:
  13270. return m_nTextureMemoryUsedPicMip2;
  13271. default:
  13272. return 0;
  13273. }
  13274. }
  13275. // Allocate and delete query objects.
  13276. ShaderAPIOcclusionQuery_t CShaderAPIDx8::CreateOcclusionQueryObject( void )
  13277. {
  13278. // don't allow this on <80 because it falls back to wireframe in that case
  13279. if( m_DeviceSupportsCreateQuery == 0 )
  13280. return INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE;
  13281. // While we're deactivated, m_OcclusionQueryObjects just holds NULL pointers.
  13282. // Create a dummy one here and let ReacquireResources create the actual D3D object.
  13283. if ( IsDeactivated() )
  13284. return INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE;
  13285. IDirect3DQuery9 *pQuery = NULL;
  13286. HRESULT hr = Dx9Device()->CreateQuery( D3DQUERYTYPE_OCCLUSION, &pQuery );
  13287. return ( hr == D3D_OK ) ? (ShaderAPIOcclusionQuery_t)pQuery : INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE;
  13288. }
  13289. void CShaderAPIDx8::DestroyOcclusionQueryObject( ShaderAPIOcclusionQuery_t handle )
  13290. {
  13291. IDirect3DQuery9 *pQuery = (IDirect3DQuery9 *)handle;
  13292. int nRetVal = pQuery->Release();
  13293. Assert( nRetVal == 0 );
  13294. }
  13295. // Bracket drawing with begin and end so that we can get counts next frame.
  13296. void CShaderAPIDx8::BeginOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t handle )
  13297. {
  13298. IDirect3DQuery9 *pQuery = (IDirect3DQuery9 *)handle;
  13299. HRESULT hResult = pQuery->Issue( D3DISSUE_BEGIN );
  13300. Assert( hResult == D3D_OK );
  13301. }
  13302. void CShaderAPIDx8::EndOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t handle )
  13303. {
  13304. IDirect3DQuery9 *pQuery = (IDirect3DQuery9 *)handle;
  13305. HRESULT hResult = pQuery->Issue( D3DISSUE_END );
  13306. Assert( hResult == D3D_OK );
  13307. }
  13308. // Get the number of pixels rendered between begin and end on an earlier frame.
  13309. // Calling this in the same frame is a huge perf hit!
  13310. int CShaderAPIDx8::OcclusionQuery_GetNumPixelsRendered( ShaderAPIOcclusionQuery_t handle, bool bFlush )
  13311. {
  13312. LOCK_SHADERAPI();
  13313. IDirect3DQuery9 *pQuery = (IDirect3DQuery9 *)handle;
  13314. DWORD nPixels;
  13315. HRESULT hResult = pQuery->GetData( &nPixels, sizeof( nPixels ), bFlush ? D3DGETDATA_FLUSH : 0 );
  13316. // This means that the query will not finish and resulted in an error, game should use
  13317. // the previous query's results and not reissue the query
  13318. if ( hResult == D3DERR_DEVICELOST )
  13319. return OCCLUSION_QUERY_RESULT_ERROR;
  13320. // This means the query isn't finished yet, game will have to use the previous query's
  13321. // results and not reissue the query; wait for query to finish later.
  13322. if ( hResult == S_FALSE )
  13323. return OCCLUSION_QUERY_RESULT_PENDING;
  13324. // NOTE: This appears to work around a driver bug for ATI on Vista
  13325. if ( nPixels & 0x80000000 )
  13326. {
  13327. nPixels = 0;
  13328. }
  13329. return nPixels;
  13330. }
  13331. void CShaderAPIDx8::SetPixelShaderFogParams( int reg, ShaderFogMode_t fogMode )
  13332. {
  13333. m_DelayedShaderConstants.iPixelShaderFogParams = reg; //save it off in case the ShaderFogMode_t disables fog. We only find out later.
  13334. float fogParams[4];
  13335. MaterialFogMode_t pixelFogMode = GetSceneFogMode();
  13336. if( (pixelFogMode != MATERIAL_FOG_NONE) && ( fogMode != SHADER_FOGMODE_DISABLED ) )
  13337. {
  13338. float ooFogRange = 1.0f;
  13339. float fStart = m_VertexShaderFogParams[0];
  13340. float fEnd = m_VertexShaderFogParams[1];
  13341. // Check for divide by zero
  13342. if ( fEnd != fStart )
  13343. {
  13344. ooFogRange = 1.0f / ( fEnd - fStart );
  13345. }
  13346. // Fixed-function-blended per-vertex fog requires some inverted params since a fog factor of 0 means fully fogged and 1 means no fog.
  13347. // We could implement shader fog the same way, but would require an extra subtract in the vertex and/or pixel shader, which we want to avoid.
  13348. fogParams[0] = 1.0f - ooFogRange * fEnd; // -start / ( fogEnd - fogStart )
  13349. fogParams[1] = m_DynamicState.m_FogZ; // water height
  13350. fogParams[2] = clamp( m_flFogMaxDensity, 0.0f, 1.0f ); // Max fog density
  13351. fogParams[3] = ooFogRange; // 1 / ( fogEnd - fogStart );
  13352. }
  13353. else
  13354. {
  13355. // Fixed-function-blended per-vertex fog requires some inverted params since a fog factor of 0 means fully fogged and 1 means no fog.
  13356. // We could implement shader fog the same way, but would require an extra subtract in the vertex and/or pixel shader, which we want to avoid.
  13357. //emulating MATERIAL_FOG_NONE by setting the parameters so that CalcRangeFog() always returns 0. Gets rid of a dynamic combo across the ps2x set.
  13358. fogParams[0] = 0.0f;
  13359. fogParams[1] = -FLT_MAX;
  13360. fogParams[2] = 0.0f;
  13361. fogParams[3] = 0.0f;
  13362. }
  13363. // cFogEndOverFogRange, cFogOne, unused, cOOFogRange
  13364. SetPixelShaderConstantInternal( reg, fogParams, 1 );
  13365. }
  13366. void CShaderAPIDx8::SetPixelShaderFogParams( int reg )
  13367. {
  13368. ShadowState_t const *pState = m_TransitionTable.CurrentShadowState();
  13369. if ( pState )
  13370. {
  13371. SetPixelShaderFogParams( reg, pState->m_FogAndMiscState.FogMode() );
  13372. }
  13373. else
  13374. {
  13375. // Have to do this so that m_DelayedShaderConstants.iPixelShaderFogParams gets updated so that we
  13376. // get this set properly when the currnent shadow state is set. If we don't do this, the
  13377. // first draw call of every frame will not get a fog constant set.
  13378. SetPixelShaderFogParams( reg, SHADER_FOGMODE_DISABLED );
  13379. }
  13380. }
  13381. void CShaderAPIDx8::SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture )
  13382. {
  13383. LOCK_SHADERAPI();
  13384. SetFlashlightStateEx( state, worldToTexture, NULL );
  13385. }
  13386. FORCEINLINE float ShadowAttenFromState( const FlashlightState_t &state )
  13387. {
  13388. // DX10 requires some hackery due to sRGB/blend ordering change from DX9, which makes the shadows too light
  13389. if ( g_pHardwareConfig->UsesSRGBCorrectBlending() )
  13390. return state.m_flShadowAtten * 0.1f; // magic number
  13391. return state.m_flShadowAtten;
  13392. }
  13393. FORCEINLINE float ShadowFilterFromState( const FlashlightState_t &state )
  13394. {
  13395. // We developed shadow maps at 1024, so we expect the penumbra size to have been tuned relative to that
  13396. return state.m_flShadowFilterSize / 1024.0f;
  13397. }
  13398. FORCEINLINE void HashShadow2DJitter( const float fJitterSeed, float *fU, float* fV )
  13399. {
  13400. const int nTexRes = 128;
  13401. int nSeed = fmod (fJitterSeed, 1.0f) * nTexRes * nTexRes;
  13402. int nRow = nSeed / nTexRes;
  13403. int nCol = nSeed % nTexRes;
  13404. // Div and mod to get an individual texel in the fTexRes x fTexRes grid
  13405. *fU = nRow / (float) nTexRes; // Row
  13406. *fV = nCol / (float) nTexRes; // Column
  13407. }
  13408. void SetupUberlightFromState( UberlightRenderState_t *pUberlight, const FlashlightState_t &state )
  13409. {
  13410. // Bail if we can't do ps30 or we don't even want an uberlight
  13411. if ( !( g_pHardwareConfig->GetDXSupportLevel() < 95 ) || !state.m_bUberlight )
  13412. return;
  13413. const UberlightState_t &u = state.m_uberlightState;
  13414. // Trap values to prevent dividing by zero
  13415. float flNearEdge = u.m_fNearEdge < 0.0001f ? 0.001f : u.m_fNearEdge;
  13416. float flFarEdge = u.m_fFarEdge < 0.0001f ? 0.001f : u.m_fFarEdge;
  13417. float flRoundness = u.m_fRoundness < 0.0001f ? 0.001f : u.m_fRoundness;
  13418. // Set uberlight shader parameters as function of user controls from UberlightState_t
  13419. pUberlight->m_vSmoothEdge0.Init( 0.0f, u.m_fCutOn - u.m_fNearEdge, u.m_fCutOff, 0.0f );
  13420. pUberlight->m_vSmoothEdge1.Init( 0.0f, u.m_fCutOn, u.m_fCutOff + u.m_fFarEdge, 0.0f );
  13421. pUberlight->m_vSmoothOneOverW.Init( 0.0f, 1.0f / flNearEdge, 1.0f / flFarEdge, 0.0f );
  13422. pUberlight->m_vShearRound.Init( u.m_fShearx, u.m_fSheary, 2.0f / flRoundness, -u.m_fRoundness / 2.0f );
  13423. pUberlight->m_vaAbB.Init( u.m_fWidth, u.m_fWidth + u.m_fWedge, u.m_fHeight, u.m_fHeight + u.m_fHedge );
  13424. QAngle angles;
  13425. QuaternionAngles( state.m_quatOrientation, angles );
  13426. // World to Light's View matrix
  13427. VMatrix viewMatrixInverse;
  13428. viewMatrixInverse.SetupMatrixOrgAngles( state.m_vecLightOrigin, angles );
  13429. MatrixInverseGeneral( viewMatrixInverse, pUberlight->m_WorldToLight );
  13430. }
  13431. ConVar r_flashlightbrightness( "r_flashlightbrightness", "0.25", FCVAR_CHEAT );
  13432. void CShaderAPIDx8::SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture )
  13433. {
  13434. LOCK_SHADERAPI();
  13435. // fixme: do a test here.
  13436. m_FlashlightState = state;
  13437. m_FlashlightWorldToTexture = worldToTexture;
  13438. m_pFlashlightDepthTexture = pFlashlightDepthTexture;
  13439. if ( g_pHardwareConfig->GetDXSupportLevel() < 92 )
  13440. {
  13441. m_FlashlightState.m_bEnableShadows = false;
  13442. m_pFlashlightDepthTexture = NULL;
  13443. }
  13444. // FIXME: This is shader specific code, only in here because of the command-buffer
  13445. // stuff required to make the 360 be fast. We need this to be in the shader DLLs,
  13446. // callable from shaderapidx8 in a fast way somehow.
  13447. // Cache off pixel shader + vertex shader values
  13448. m_pFlashlightAtten[0] = m_FlashlightState.m_fConstantAtten; // Set the flashlight attenuation factors
  13449. m_pFlashlightAtten[1] = m_FlashlightState.m_fLinearAtten;
  13450. m_pFlashlightAtten[2] = m_FlashlightState.m_fQuadraticAtten;
  13451. m_pFlashlightAtten[3] = m_FlashlightState.m_FarZAtten;
  13452. m_pFlashlightPos[0] = m_FlashlightState.m_vecLightOrigin[0]; // Set the flashlight origin
  13453. m_pFlashlightPos[1] = m_FlashlightState.m_vecLightOrigin[1];
  13454. m_pFlashlightPos[2] = m_FlashlightState.m_vecLightOrigin[2];
  13455. m_pFlashlightPos[3] = m_FlashlightState.m_FarZ;
  13456. float flFlashlightScale = r_flashlightbrightness.GetFloat();
  13457. if ( IsPC() && !g_pHardwareConfig->GetHDREnabled() )
  13458. {
  13459. // Non-HDR path requires 2.0 flashlight
  13460. flFlashlightScale = 2.0f;
  13461. }
  13462. flFlashlightScale *= m_FlashlightState.m_fBrightnessScale;
  13463. // Generate pixel shader constant
  13464. float const *pFlashlightColor = m_FlashlightState.m_Color;
  13465. m_pFlashlightColor[0] = flFlashlightScale * pFlashlightColor[0];
  13466. m_pFlashlightColor[1] = flFlashlightScale * pFlashlightColor[1];
  13467. m_pFlashlightColor[2] = flFlashlightScale * pFlashlightColor[2];
  13468. m_pFlashlightColor[3] = pFlashlightColor[3]; // not used, will be whacked by ExecuteCommandBuffer
  13469. // Red flashlight for testing
  13470. //m_pFlashlightColor[0] = 0.5f; m_pFlashlightColor[1] = 0.0f; m_pFlashlightColor[2] = 0.0f;
  13471. m_pFlashlightTweaks[0] = ShadowFilterFromState( m_FlashlightState );
  13472. m_pFlashlightTweaks[1] = ShadowAttenFromState( m_FlashlightState );
  13473. HashShadow2DJitter( m_FlashlightState.m_flShadowJitterSeed, &m_pFlashlightTweaks[2], &m_pFlashlightTweaks[3] );
  13474. if ( !IsX360() )
  13475. {
  13476. SetupUberlightFromState( &m_UberlightRenderState, m_FlashlightState );
  13477. }
  13478. }
  13479. const FlashlightState_t &CShaderAPIDx8::GetFlashlightState( VMatrix &worldToTexture ) const
  13480. {
  13481. worldToTexture = m_FlashlightWorldToTexture;
  13482. return m_FlashlightState;
  13483. }
  13484. const FlashlightState_t &CShaderAPIDx8::GetFlashlightStateEx( VMatrix &worldToTexture, ITexture **ppFlashlightDepthTexture ) const
  13485. {
  13486. worldToTexture = m_FlashlightWorldToTexture;
  13487. *ppFlashlightDepthTexture = m_pFlashlightDepthTexture;
  13488. return m_FlashlightState;
  13489. }
  13490. void CShaderAPIDx8::GetFlashlightShaderInfo( bool *pShadowsEnabled, bool *pUberLight ) const
  13491. {
  13492. // Adding NULL ptr check on m_pFlashlightDepthTexture here so we slam the FLASHLIGHTSHADOWS dynamic combo off if a flashlight depth texture isn't actually bound (otherwise we set a TEXTURE_WHITE texture,
  13493. // which isn't depth which results in the pixel shader sampling a regular color texture as depth)
  13494. *pShadowsEnabled = m_FlashlightState.m_bEnableShadows && ( m_pFlashlightDepthTexture != NULL );
  13495. *pUberLight = m_FlashlightState.m_bUberlight;
  13496. }
  13497. float CShaderAPIDx8::GetFlashlightAmbientOcclusion( ) const
  13498. {
  13499. return m_FlashlightState.m_flAmbientOcclusion;
  13500. }
  13501. bool CShaderAPIDx8::SupportsMSAAMode( int nMSAAMode )
  13502. {
  13503. if ( IsX360() )
  13504. {
  13505. return false;
  13506. }
  13507. if ( m_PresentParameters.BackBufferFormat == D3DFMT_UNKNOWN )
  13508. {
  13509. // Autodetection code running during application startup:
  13510. return ( D3D_OK == D3D()->CheckDeviceMultiSampleType( m_DisplayAdapter, DX8_DEVTYPE,
  13511. D3DFMT_A8R8G8B8,
  13512. false,
  13513. ComputeMultisampleType( nMSAAMode ), NULL ) );
  13514. }
  13515. return ( D3D_OK == D3D()->CheckDeviceMultiSampleType( m_DisplayAdapter, m_DeviceType,
  13516. m_PresentParameters.BackBufferFormat,
  13517. m_PresentParameters.Windowed,
  13518. ComputeMultisampleType( nMSAAMode ), NULL ) );
  13519. }
  13520. bool CShaderAPIDx8::SupportsCSAAMode( int nNumSamples, int nQualityLevel )
  13521. {
  13522. #ifdef DX_TO_GL_ABSTRACTION
  13523. return false;
  13524. #endif
  13525. // Only nVidia does this kind of AA
  13526. if ( g_pHardwareConfig->Caps().m_VendorID != VENDORID_NVIDIA )
  13527. return false;
  13528. DWORD dwQualityLevels = 0;
  13529. HRESULT hr = D3D()->CheckDeviceMultiSampleType( m_DisplayAdapter, m_DeviceType,
  13530. m_PresentParameters.BackBufferFormat,
  13531. m_PresentParameters.Windowed,
  13532. ComputeMultisampleType( nNumSamples ), &dwQualityLevels );
  13533. return ( ( D3D_OK == hr ) && ( (int) dwQualityLevels >= nQualityLevel ) );
  13534. }
  13535. void CShaderAPIDx8::BeginGeneratingCSMs()
  13536. {
  13537. m_bGeneratingCSMs = true;
  13538. if ( mat_depthwrite_new_path.GetBool() )
  13539. {
  13540. // Set bunch of render states for shadow drawing
  13541. SetRenderStateForce( D3DRS_ZWRITEENABLE, TRUE );
  13542. SetRenderStateForce( D3DRS_ZENABLE, D3DZB_TRUE );
  13543. SetRenderStateForce( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
  13544. SetRenderStateForce( D3DRS_DEPTHBIAS, 0.0f );
  13545. SetRenderStateForce( D3DRS_COLORWRITEENABLE, 0 );
  13546. SetRenderStateForce( D3DRS_ALPHATESTENABLE, FALSE );
  13547. SetRenderStateForce( D3DRS_FILLMODE, D3DFILL_SOLID );
  13548. // Disable culling
  13549. ApplyCullEnable( false );
  13550. }
  13551. }
  13552. void CShaderAPIDx8::EndGeneratingCSMs()
  13553. {
  13554. if ( mat_depthwrite_new_path.GetBool() )
  13555. {
  13556. SetRenderStateForce( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_BLUE |
  13557. D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_ALPHA );
  13558. SetRenderStateForce( D3DRS_DEPTHBIAS, 0.0f );
  13559. float fShadowSlopeScaleDepthBias = 0.0f;
  13560. SetRenderStateForce( D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&fShadowSlopeScaleDepthBias );
  13561. // Re-enable culling
  13562. ApplyCullEnable( true );
  13563. }
  13564. m_bGeneratingCSMs = false;
  13565. m_bCSMsValidThisFrame = true;
  13566. }
  13567. void CShaderAPIDx8::PerpareForCascadeDraw( int cascade, float fShadowSlopeScaleDepthBias, float fShadowDepthBias )
  13568. {
  13569. if ( mat_depthwrite_new_path.GetBool() )
  13570. {
  13571. SetRenderStateForce( D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&fShadowSlopeScaleDepthBias );
  13572. SetRenderState( D3DRS_DEPTHBIAS, *((DWORD*) (&fShadowDepthBias)) );
  13573. }
  13574. }
  13575. void CShaderAPIDx8::SetShadowDepthBiasFactors( float fShadowSlopeScaleDepthBias, float fShadowDepthBias )
  13576. {
  13577. m_fShadowSlopeScaleDepthBias = fShadowSlopeScaleDepthBias;
  13578. m_fShadowDepthBias = fShadowDepthBias;
  13579. m_TransitionTable.SetShadowDepthBiasValuesDirty( true );
  13580. if ( m_TransitionTable.CurrentShadowState() && m_TransitionTable.CurrentShadowState()->m_DepthTestState.m_ZBias == SHADER_POLYOFFSET_SHADOW_BIAS )
  13581. {
  13582. // Need to set the render state here right away, because changing bias values between different draws
  13583. // using the same depthwrite shader won't apply the snapshot again.
  13584. ApplyZBias( m_TransitionTable.CurrentShadowState()->m_DepthTestState );
  13585. }
  13586. }
  13587. void CShaderAPIDx8::ClearVertexAndPixelShaderRefCounts()
  13588. {
  13589. LOCK_SHADERAPI();
  13590. ShaderManager()->ClearVertexAndPixelShaderRefCounts();
  13591. }
  13592. void CShaderAPIDx8::PurgeUnusedVertexAndPixelShaders()
  13593. {
  13594. LOCK_SHADERAPI();
  13595. ShaderManager()->PurgeUnusedVertexAndPixelShaders();
  13596. }
  13597. bool CShaderAPIDx8::UsingSoftwareVertexProcessing() const
  13598. {
  13599. return g_pHardwareConfig->Caps().m_bSoftwareVertexProcessing;
  13600. }
  13601. ITexture *CShaderAPIDx8::GetRenderTargetEx( int nRenderTargetID ) const
  13602. {
  13603. return ShaderUtil()->GetRenderTargetEx( nRenderTargetID );
  13604. }
  13605. void CShaderAPIDx8::SetToneMappingScaleLinear( const Vector &scale )
  13606. {
  13607. Vector scale_to_use = scale;
  13608. m_ToneMappingScale.AsVector3D() = scale_to_use;
  13609. bool mode_uses_srgb=false;
  13610. switch( HardwareConfig()->GetHDRType() )
  13611. {
  13612. case HDR_TYPE_NONE:
  13613. m_ToneMappingScale.x = 1.0; // output scale
  13614. m_ToneMappingScale.z = 1.0; // reflection map scale
  13615. break;
  13616. case HDR_TYPE_FLOAT:
  13617. m_ToneMappingScale.x = scale_to_use.x; // output scale
  13618. m_ToneMappingScale.z = 1.0; // reflection map scale
  13619. break;
  13620. case HDR_TYPE_INTEGER:
  13621. mode_uses_srgb = true;
  13622. m_ToneMappingScale.x = scale_to_use.x; // output scale
  13623. m_ToneMappingScale.z = 16.0; // reflection map scale
  13624. break;
  13625. }
  13626. #ifdef _PS3
  13627. // We're using floating point cubemaps but not the full HDR_TYPE_FLOAT codepath
  13628. m_ToneMappingScale.z = 1.0f;
  13629. #endif // _PS3
  13630. m_ToneMappingScale.y = g_pHardwareConfig->GetLightMapScaleFactor(); // light map scale
  13631. // w component gets gamma scale
  13632. m_ToneMappingScale.w = LinearToGammaFullRange( m_ToneMappingScale.x );
  13633. // For people trying to search the shader cpp code trying to figure out where these constants get set:
  13634. // TONE_MAPPING_SCALE_PSH_CONSTANT == PSREG_LIGHT_SCALE (same register)
  13635. // This is the same constant as cLightScale which corresponds to LINEAR_LIGHT_SCALE, LIGHT_MAP_SCALE, ENV_MAP_SCALE, and GAMMA_LIGHT_SCALE
  13636. SetPixelShaderConstantInternal( TONE_MAPPING_SCALE_PSH_CONSTANT, m_ToneMappingScale.Base() );
  13637. RegenerateFogConstants();
  13638. // We have to change the fog color since we tone map directly in the shaders in integer HDR mode.
  13639. if ( HardwareConfig()->GetHDRType() == HDR_TYPE_INTEGER && m_TransitionTable.CurrentShadowState() )
  13640. {
  13641. // Get the shadow state in sync since it depends on SetToneMappingScaleLinear.
  13642. ApplyFogMode( m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.FogMode(), m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_bVertexFogEnable, mode_uses_srgb, m_TransitionTable.CurrentShadowState()->m_FogAndMiscState.m_bDisableFogGammaCorrection );
  13643. }
  13644. }
  13645. const Vector & CShaderAPIDx8::GetToneMappingScaleLinear( void ) const
  13646. {
  13647. return m_ToneMappingScale.AsVector3D();
  13648. }
  13649. void CShaderAPIDx8::EnableLinearColorSpaceFrameBuffer( bool bEnable )
  13650. {
  13651. LOCK_SHADERAPI();
  13652. m_TransitionTable.EnableLinearColorSpaceFrameBuffer( bEnable );
  13653. }
  13654. void CShaderAPIDx8::SetFloatRenderingParameter( int parm_number, float value )
  13655. {
  13656. LOCK_SHADERAPI();
  13657. if ( parm_number < ARRAYSIZE( FloatRenderingParameters ))
  13658. FloatRenderingParameters[parm_number] = value;
  13659. }
  13660. void CShaderAPIDx8::SetIntRenderingParameter( int parm_number, int value )
  13661. {
  13662. LOCK_SHADERAPI();
  13663. if ( parm_number < ARRAYSIZE( IntRenderingParameters ))
  13664. IntRenderingParameters[parm_number] = value;
  13665. }
  13666. void CShaderAPIDx8::SetTextureRenderingParameter( int parm_number, ITexture *pTexture )
  13667. {
  13668. LOCK_SHADERAPI();
  13669. if ( parm_number < ARRAYSIZE( TextureRenderingParameters ))
  13670. TextureRenderingParameters[parm_number] = pTexture;
  13671. }
  13672. void CShaderAPIDx8::SetVectorRenderingParameter( int parm_number, Vector const & value )
  13673. {
  13674. LOCK_SHADERAPI();
  13675. if ( parm_number < ARRAYSIZE( VectorRenderingParameters ))
  13676. VectorRenderingParameters[parm_number] = value;
  13677. }
  13678. float CShaderAPIDx8::GetFloatRenderingParameter( int parm_number ) const
  13679. {
  13680. LOCK_SHADERAPI();
  13681. if ( parm_number < ARRAYSIZE( FloatRenderingParameters ))
  13682. return FloatRenderingParameters[parm_number];
  13683. else
  13684. return 0.0;
  13685. }
  13686. int CShaderAPIDx8::GetIntRenderingParameter( int parm_number ) const
  13687. {
  13688. LOCK_SHADERAPI();
  13689. if ( parm_number < ARRAYSIZE( IntRenderingParameters ))
  13690. return IntRenderingParameters[parm_number];
  13691. else
  13692. return 0;
  13693. }
  13694. ITexture *CShaderAPIDx8::GetTextureRenderingParameter( int parm_number ) const
  13695. {
  13696. LOCK_SHADERAPI();
  13697. if ( parm_number < ARRAYSIZE( TextureRenderingParameters ))
  13698. return TextureRenderingParameters[parm_number];
  13699. else
  13700. return 0;
  13701. }
  13702. Vector CShaderAPIDx8::GetVectorRenderingParameter( int parm_number ) const
  13703. {
  13704. LOCK_SHADERAPI();
  13705. if ( parm_number < ARRAYSIZE( VectorRenderingParameters ))
  13706. return VectorRenderingParameters[parm_number];
  13707. else
  13708. return Vector( 0, 0, 0 );
  13709. }
  13710. #if defined( _GAMECONSOLE )
  13711. void CShaderAPIDx8::BeginConsoleZPass2( int nNumSpilloverIndicesNeeded )
  13712. {
  13713. bool bEnableZPass = true;
  13714. if ( MeshMgr()->GetDynamicIndexBufferIndicesLeft() < nNumSpilloverIndicesNeeded )
  13715. {
  13716. bEnableZPass = false;
  13717. // TODO: If nNumDynamicIndicesNeeded <= GetDynamicIBAllocationCount() we could potentially flush the dynamic IB completely
  13718. // and start filling it from the beginning, enabling the z pass
  13719. }
  13720. if ( bEnableZPass )
  13721. {
  13722. Assert( m_bInZPass == false );
  13723. // reset renderstate to make sure the Zfunc is set to a state that's compatible with the Z pass
  13724. m_TransitionTable.UseSnapshot( m_zPassSnapshot );
  13725. Dx9Device()->BeginZPass( 0 );
  13726. #if defined( _X360 )
  13727. // set up predicated vertexshader GPR allocations so that we max out VS threads in the Z pass and
  13728. // use the currently requested alloction for the main render pass
  13729. Dx9Device()->SetPredication( D3DPRED_ALL_Z );
  13730. Dx9Device()->SetShaderGPRAllocation( D3DSETALLOCATION_PREDICATED, 96, 32 );
  13731. Dx9Device()->SetPredication( 0 );
  13732. // this function knows about predication inside of a zpass block
  13733. CommitShaderGPRs( Dx9Device(), m_DesiredState, m_DynamicState, true );
  13734. #else
  13735. Dx9Device()->SetPredication( 0 ); // just disable predication
  13736. #endif
  13737. m_bInZPass = true;
  13738. m_nZPassCounter++;
  13739. }
  13740. else
  13741. {
  13742. #ifndef _PS3
  13743. Warning( "Cannot satisfy Console Z pass request due to large dynamic index count (indices left %d < spilloever %d). Tell Thorsten.\n", MeshMgr()->GetDynamicIndexBufferIndicesLeft(), nNumSpilloverIndicesNeeded );
  13744. #endif
  13745. }
  13746. }
  13747. void CShaderAPIDx8::EndConsoleZPass()
  13748. {
  13749. if ( m_bInZPass )
  13750. {
  13751. m_bInZPass = false;
  13752. // reset all command predication
  13753. Dx9Device()->SetPredication( 0 );
  13754. HRESULT retVal = Dx9Device()->EndZPass();
  13755. if ( retVal != S_OK )
  13756. {
  13757. Warning( "EndConsoleZPass() failed! Tell Thorsten.\n" );
  13758. }
  13759. #if defined( _X360 )
  13760. // Reset shader GPRs un-predicated
  13761. CommitShaderGPRs( Dx9Device(), m_DesiredState, m_DynamicState, true );
  13762. #endif
  13763. }
  13764. }
  13765. void CShaderAPIDx8::EnablePredication( bool bZPass, bool bRenderPass )
  13766. {
  13767. DWORD mask = 0;
  13768. mask |= bZPass ? D3DPRED_ALL_Z : 0;
  13769. mask |= bRenderPass ? D3DPRED_ALL_RENDER : 0;
  13770. Dx9Device()->SetPredication( mask );
  13771. }
  13772. void CShaderAPIDx8::DisablePredication()
  13773. {
  13774. Dx9Device()->SetPredication( 0 );
  13775. }
  13776. #endif
  13777. // stencil entry points
  13778. void CShaderAPIDx8::GetCurrentStencilState( ShaderStencilState_t *pState )
  13779. {
  13780. pState->m_bEnable = ( m_DynamicState.m_RenderState[D3DRS_STENCILENABLE] == ( (DWORD) TRUE ) );
  13781. pState->m_FailOp = (ShaderStencilOp_t)( m_DynamicState.m_RenderState[D3DRS_STENCILFAIL] );
  13782. pState->m_ZFailOp = (ShaderStencilOp_t)( m_DynamicState.m_RenderState[D3DRS_STENCILZFAIL] );
  13783. pState->m_PassOp = (ShaderStencilOp_t)( m_DynamicState.m_RenderState[D3DRS_STENCILPASS] );
  13784. pState->m_CompareFunc = (ShaderStencilFunc_t)( m_DynamicState.m_RenderState[D3DRS_STENCILFUNC] );
  13785. pState->m_nReferenceValue = m_DynamicState.m_RenderState[D3DRS_STENCILREF];
  13786. pState->m_nTestMask = m_DynamicState.m_RenderState[D3DRS_STENCILMASK];
  13787. pState->m_nWriteMask = m_DynamicState.m_RenderState[D3DRS_STENCILWRITEMASK];
  13788. #if defined( _X360 )
  13789. pState->m_bHiStencilEnable = ( m_DynamicState.m_RenderState[D3DRS_HISTENCILENABLE] == TRUE );
  13790. pState->m_bHiStencilWriteEnable = ( m_DynamicState.m_RenderState[D3DRS_HISTENCILWRITEENABLE] == TRUE );
  13791. pState->m_HiStencilCompareFunc = (ShaderHiStencilFunc_t)( m_DynamicState.m_RenderState[D3DRS_HISTENCILFUNC] );
  13792. pState->m_nHiStencilReferenceValue = m_DynamicState.m_RenderState[D3DRS_HISTENCILREF];
  13793. #endif
  13794. }
  13795. //#define WORKAROUND_DEBUG_SHADERAPI_ERRORS
  13796. void CShaderAPIDx8::SetStencilStateInternal( const ShaderStencilState_t &state )
  13797. {
  13798. #ifdef WORKAROUND_DEBUG_SHADERAPI_ERRORS
  13799. if ( m_bInZPass )
  13800. {
  13801. SetRenderState( D3DRS_STENCILENABLE, FALSE );
  13802. }
  13803. else
  13804. {
  13805. SetRenderState( D3DRS_STENCILENABLE, state.m_bEnable ? TRUE:FALSE );
  13806. }
  13807. #else
  13808. SetRenderState( D3DRS_STENCILENABLE, state.m_bEnable ? TRUE:FALSE );
  13809. #endif
  13810. #if defined( _X360 )
  13811. SetRenderState( D3DRS_HISTENCILENABLE, mat_hi_stencil_enable.GetBool() ? state.m_bHiStencilEnable : FALSE );
  13812. SetRenderState( D3DRS_HISTENCILWRITEENABLE, state.m_bHiStencilWriteEnable );
  13813. SetRenderState( D3DRS_HISTENCILFUNC, state.m_HiStencilCompareFunc );
  13814. SetRenderState( D3DRS_HISTENCILREF, state.m_nHiStencilReferenceValue );
  13815. #endif
  13816. if ( !state.m_bEnable )
  13817. return;
  13818. SetRenderState( D3DRS_STENCILFAIL, state.m_FailOp );
  13819. SetRenderState( D3DRS_STENCILZFAIL, state.m_ZFailOp );
  13820. SetRenderState( D3DRS_STENCILPASS, state.m_PassOp );
  13821. SetRenderState( D3DRS_STENCILFUNC, state.m_CompareFunc );
  13822. SetRenderState( D3DRS_STENCILREF, state.m_nReferenceValue );
  13823. SetRenderState( D3DRS_STENCILMASK, state.m_nTestMask );
  13824. SetRenderState( D3DRS_STENCILWRITEMASK, state.m_nWriteMask );
  13825. }
  13826. void CShaderAPIDx8::SetStencilState( const ShaderStencilState_t &state )
  13827. {
  13828. LOCK_SHADERAPI();
  13829. #ifdef _DEBUG
  13830. if ( state.m_bEnable && state.m_CompareFunc == SHADER_STENCILFUNC_ALWAYS )
  13831. {
  13832. AssertMsg( state.m_FailOp == SHADER_STENCILOP_KEEP, "Always set failop to keep when comparefunc is always for hi-z perf reasons" );
  13833. }
  13834. #endif
  13835. SetStencilStateInternal( state );
  13836. }
  13837. void CShaderAPIDx8::ClearStencilBufferRectangle(
  13838. int xmin, int ymin, int xmax, int ymax,int value)
  13839. {
  13840. LOCK_SHADERAPI();
  13841. D3DRECT clear;
  13842. clear.x1 = xmin;
  13843. clear.y1 = ymin;
  13844. clear.x2 = xmax;
  13845. clear.y2 = ymax;
  13846. Dx9Device()->Clear(
  13847. 1, &clear, D3DCLEAR_STENCIL, 0, 0, value );
  13848. }
  13849. #if defined( _X360 )
  13850. // Flush Hi-Stencil changes to Hierarchical Z/Stencil tile memory. Introduces about 2000 cycle stall on GPU.
  13851. // There's an asynchronous flush, but it's less robust, so we'll take the stall for now.
  13852. void CShaderAPIDx8::FlushHiStencil()
  13853. {
  13854. LOCK_SHADERAPI();
  13855. Dx9Device()->FlushHiZStencil( D3DFHZS_SYNCHRONOUS );
  13856. }
  13857. #endif
  13858. void CShaderAPIDx8::AntiAliasingHint( int nHint )
  13859. {
  13860. #if defined( _PS3 )
  13861. Dx9Device()->AntiAliasingHint( nHint );
  13862. #endif
  13863. }
  13864. #if defined( _PS3 )
  13865. void CShaderAPIDx8::FlushTextureCache()
  13866. {
  13867. Dx9Device()->FlushTextureCache();
  13868. }
  13869. #endif // _PS3
  13870. int CShaderAPIDx8::CompareSnapshots( StateSnapshot_t snapshot0, StateSnapshot_t snapshot1 )
  13871. {
  13872. LOCK_SHADERAPI();
  13873. const ShadowState_t &shadow0 = m_TransitionTable.GetSnapshot(snapshot0);
  13874. const ShadowState_t &shadow1 = m_TransitionTable.GetSnapshot(snapshot1);
  13875. const ShadowShaderState_t &shader0 = m_TransitionTable.GetSnapshotShader(snapshot0);
  13876. const ShadowShaderState_t &shader1 = m_TransitionTable.GetSnapshotShader(snapshot1);
  13877. int dVertex = shader0.m_VertexShader - shader1.m_VertexShader;
  13878. if ( dVertex )
  13879. return dVertex;
  13880. int dVCombo = shader0.m_nStaticVshIndex - shader1.m_nStaticVshIndex;
  13881. if ( dVCombo)
  13882. return dVCombo;
  13883. int dPixel = shader0.m_PixelShader - shader1.m_PixelShader;
  13884. if ( dPixel )
  13885. return dPixel;
  13886. int dPCombo = shader0.m_nStaticPshIndex - shader1.m_nStaticPshIndex;
  13887. if ( dPCombo)
  13888. return dPCombo;
  13889. return snapshot0 - snapshot1;
  13890. }
  13891. //-----------------------------------------------------------------------------
  13892. // X360 TTF support requires XUI state manipulation of d3d.
  13893. // Font support lives inside the shaderapi in order to maintain privacy of d3d.
  13894. //-----------------------------------------------------------------------------
  13895. #if defined( _X360 )
  13896. HXUIFONT CShaderAPIDx8::OpenTrueTypeFont( const char *pFontname, int tall, int style )
  13897. {
  13898. LOCK_SHADERAPI();
  13899. struct FontTable_t
  13900. {
  13901. const char *pFontName;
  13902. const char *pPath;
  13903. bool m_bRestrictiveLoadIntoMemory;
  13904. bool m_bAlwaysLoadIntoMemory;
  13905. };
  13906. // explicit mapping required, dvd searching too expensive
  13907. static FontTable_t s_pFontToFilename[] =
  13908. {
  13909. #include "fontremaptable.h"
  13910. };
  13911. MEM_ALLOC_CREDIT_( "CShaderAPIDx8::OpenTrueTypeFont ( -> Xui*)" );
  13912. // remap typeface to diskname
  13913. const char *pDiskname = NULL;
  13914. bool bUsingInMemoryFont = false;
  13915. for ( int i = 0; i < ARRAYSIZE( s_pFontToFilename ); i++ )
  13916. {
  13917. if ( !V_stricmp( pFontname, s_pFontToFilename[i].pFontName ) )
  13918. {
  13919. pDiskname = s_pFontToFilename[i].pPath;
  13920. // force all the names rto be normalized, want Courier to match to courier to COURIER
  13921. pFontname = s_pFontToFilename[i].pFontName;
  13922. bUsingInMemoryFont = s_pFontToFilename[i].m_bAlwaysLoadIntoMemory;
  13923. if ( XBX_IsRestrictiveLanguage() && s_pFontToFilename[i].m_bRestrictiveLoadIntoMemory )
  13924. {
  13925. bUsingInMemoryFont = true;
  13926. }
  13927. break;
  13928. }
  13929. }
  13930. if ( !pDiskname )
  13931. {
  13932. // not found
  13933. DevMsg( "True Type Font: '%s' unknown.\n", pFontname );
  13934. return NULL;
  13935. }
  13936. // font will be registered using the !!!Table's!!! typeface name
  13937. wchar_t wchFontname[MAX_PATH];
  13938. Q_UTF8ToUnicode( pFontname, wchFontname, sizeof( wchFontname ) );
  13939. // find font in registered typefaces
  13940. TypefaceDescriptor *pDescriptors = NULL;
  13941. DWORD numTypeFaces = 0;
  13942. HRESULT hr = XuiEnumerateTypefaces( &pDescriptors, &numTypeFaces );
  13943. if ( FAILED( hr ) )
  13944. {
  13945. return NULL;
  13946. }
  13947. bool bRegistered = false;
  13948. for ( DWORD i=0; i<numTypeFaces; i++ )
  13949. {
  13950. if ( !V_wcscmp( pDescriptors[i].szTypeface, wchFontname ) )
  13951. {
  13952. bRegistered = true;
  13953. break;
  13954. }
  13955. }
  13956. // release enumeration query
  13957. XuiDestroyTypefaceList( pDescriptors, numTypeFaces );
  13958. if ( !bRegistered )
  13959. {
  13960. char filename[MAX_PATH];
  13961. if ( bUsingInMemoryFont )
  13962. {
  13963. void *pMemory = NULL;
  13964. int nAlignedSize = 0;
  13965. int nFileSize = 0;
  13966. int iMapIndex = m_XboxFontMemoryDict.Find( pFontname );
  13967. if ( iMapIndex == m_XboxFontMemoryDict.InvalidIndex() )
  13968. {
  13969. V_snprintf( filename, sizeof( filename ), "d:/%s", pDiskname );
  13970. V_FixSlashes( filename, '/' );
  13971. nFileSize = g_pFullFileSystem->Size( filename, NULL );
  13972. if ( nFileSize <= 0 )
  13973. {
  13974. return NULL;
  13975. }
  13976. // Size must be aligned to 32k for optimal load
  13977. nAlignedSize = AlignValue( nFileSize, 32 * 1024 );
  13978. pMemory = XPhysicalAlloc( nAlignedSize, MAXULONG_PTR, 0, PAGE_READWRITE );
  13979. CUtlBuffer buf;
  13980. buf.SetExternalBuffer( pMemory, nAlignedSize, 0 );
  13981. if ( !g_pFullFileSystem->ReadFile( filename, NULL, buf ) )
  13982. {
  13983. XPhysicalFree( pMemory );
  13984. return NULL;
  13985. }
  13986. iMapIndex = m_XboxFontMemoryDict.Insert( pFontname );
  13987. m_XboxFontMemoryDict[iMapIndex].m_pPhysicalMemory = pMemory;
  13988. m_XboxFontMemoryDict[iMapIndex].m_nMemorySize = nAlignedSize;
  13989. m_XboxFontMemoryDict[iMapIndex].m_nFontFileSize = nFileSize;
  13990. }
  13991. else
  13992. {
  13993. pMemory = m_XboxFontMemoryDict[iMapIndex].m_pPhysicalMemory;
  13994. nFileSize = m_XboxFontMemoryDict[iMapIndex].m_nFontFileSize;
  13995. }
  13996. V_snprintf( filename, sizeof( filename ), "memory://%X,%X", (intp)pMemory, nFileSize );
  13997. }
  13998. else
  13999. {
  14000. V_snprintf( filename, sizeof( filename ), "file://d:/%s", pDiskname );
  14001. }
  14002. V_FixSlashes( filename, '/' );
  14003. wchar_t wchFilename[MAX_PATH];
  14004. V_UTF8ToUnicode( filename, wchFilename, sizeof( wchFilename ) );
  14005. TypefaceDescriptor desc;
  14006. desc.fBaselineAdjust = 0;
  14007. desc.szFallbackTypeface = NULL;
  14008. desc.szLocator = wchFilename;
  14009. desc.szReserved1 = 0;
  14010. desc.szTypeface = wchFontname;
  14011. hr = XuiRegisterTypeface( &desc, FALSE );
  14012. if ( FAILED( hr ) )
  14013. {
  14014. return NULL;
  14015. }
  14016. }
  14017. // empirically derived factor to achieve desired cell height
  14018. float pointSize = tall * 0.59f;
  14019. HXUIFONT hFont = NULL;
  14020. hr = XuiCreateFont( wchFontname, pointSize, style, 0, &hFont );
  14021. if ( FAILED( hr ) )
  14022. {
  14023. return NULL;
  14024. }
  14025. return hFont;
  14026. }
  14027. #endif
  14028. //-----------------------------------------------------------------------------
  14029. // Release TTF
  14030. //-----------------------------------------------------------------------------
  14031. #if defined( _X360 )
  14032. void CShaderAPIDx8::CloseTrueTypeFont( HXUIFONT hFont )
  14033. {
  14034. if ( !hFont )
  14035. return;
  14036. LOCK_SHADERAPI();
  14037. XuiReleaseFont( hFont );
  14038. }
  14039. #endif
  14040. //-----------------------------------------------------------------------------
  14041. // Get the TTF Metrics
  14042. //-----------------------------------------------------------------------------
  14043. #if defined( _X360 )
  14044. bool CShaderAPIDx8::GetTrueTypeFontMetrics( HXUIFONT hFont, wchar_t wchFirst, wchar_t wchLast, XUIFontMetrics *pFontMetrics, XUICharMetrics *pCharMetrics )
  14045. {
  14046. if ( !hFont )
  14047. return false;
  14048. LOCK_SHADERAPI();
  14049. int numChars = wchLast - wchFirst + 1;
  14050. V_memset( pCharMetrics, 0, numChars * sizeof( XUICharMetrics ) );
  14051. HRESULT hr = XuiGetFontMetrics( hFont, pFontMetrics );
  14052. if ( !FAILED( hr ) )
  14053. {
  14054. // X360 issue: max character width may be too small.
  14055. // Run through each character and fixup
  14056. for ( int i = 0; i < numChars; i++ )
  14057. {
  14058. hr = XuiGetCharMetrics( hFont, wchFirst + i, pCharMetrics + i );
  14059. if ( !FAILED( hr ) )
  14060. {
  14061. float maxWidth = pCharMetrics[i].fMaxX;
  14062. if ( pCharMetrics[i].fMinX < 0 )
  14063. {
  14064. maxWidth = pCharMetrics[i].fMaxX - pCharMetrics[i].fMinX;
  14065. }
  14066. if ( maxWidth > pFontMetrics->fMaxWidth )
  14067. {
  14068. pFontMetrics->fMaxWidth = maxWidth;
  14069. }
  14070. if ( pCharMetrics[i].fAdvance > pFontMetrics->fMaxWidth )
  14071. {
  14072. pFontMetrics->fMaxWidth = pCharMetrics[i].fAdvance;
  14073. }
  14074. }
  14075. }
  14076. // Fonts are getting cut off, MaxHeight seems to be misreported smaller in some cases when fMaxDescent <= 0.
  14077. // Additionally, XuiGetFontHeight() returns the same value as pFontMetrics->fLineHeight, not fMaxHeight, so we can't use that!
  14078. // So, use MAX( fMaxHeight, ( fMaxAscent - fMaxDescent ) ) when fMaxDescent <= 0
  14079. float maxHeight = 0;
  14080. if ( pFontMetrics->fMaxDescent <= 0 )
  14081. {
  14082. // descent is negative for below baseline
  14083. maxHeight = pFontMetrics->fMaxAscent - pFontMetrics->fMaxDescent;
  14084. }
  14085. if ( maxHeight > pFontMetrics->fMaxHeight )
  14086. {
  14087. pFontMetrics->fMaxHeight = maxHeight;
  14088. }
  14089. }
  14090. return ( !FAILED( hr ) );
  14091. }
  14092. #endif
  14093. //-----------------------------------------------------------------------------
  14094. // Gets the glyph bits in rgba order. This function PURPOSELY hijacks D3D
  14095. // because XUI is involved. It is called at a very specific place in the VGUI
  14096. // render frame where its deleterious affects are going to be harmless.
  14097. //-----------------------------------------------------------------------------
  14098. #if defined( _X360 )
  14099. bool CShaderAPIDx8::GetTrueTypeGlyphs( HXUIFONT hFont, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int *pWidth, int *pHeight, unsigned char *pRGBA, int *pRGBAOffset )
  14100. {
  14101. if ( !hFont )
  14102. return false;
  14103. // Ensure this doesn't talk to D3D at the same time as the loading bar
  14104. AUTO_LOCK_FM( m_nonInteractiveModeMutex );
  14105. LOCK_SHADERAPI();
  14106. bool bSuccess = false;
  14107. IDirect3DSurface *pRTSurface = NULL;
  14108. IDirect3DSurface *pSavedSurface = NULL;
  14109. IDirect3DSurface *pSavedDepthSurface = NULL;
  14110. IDirect3DTexture *pTexture = NULL;
  14111. D3DVIEWPORT9 savedViewport;
  14112. D3DXMATRIX matView;
  14113. D3DXMATRIX matXForm;
  14114. D3DLOCKED_RECT lockedRect;
  14115. // must release resources for xui
  14116. bool bPreviousOwnState = OwnGPUResources( false );
  14117. // have to reset to default state to rasterize glyph correctly
  14118. // state will get re-established during next mesh draw
  14119. ResetRenderState( false );
  14120. Dx9Device()->SetRenderState( D3DRS_ZENABLE, FALSE );
  14121. Dx9Device()->GetRenderTarget( 0, &pSavedSurface );
  14122. Dx9Device()->GetDepthStencilSurface( &pSavedDepthSurface );
  14123. Dx9Device()->GetViewport( &savedViewport );
  14124. // Figure out the size of surface/texture we need to allocate
  14125. int rtWidth = 0;
  14126. int rtHeight = 0;
  14127. for ( int i = 0; i < numChars; i++ )
  14128. {
  14129. rtWidth += pWidth[i];
  14130. rtHeight = MAX( rtHeight, pHeight[i] );
  14131. }
  14132. // per resolve() restrictions, need to be 32 aligned
  14133. // The 64 is critical to fixing their internal clip logic. Apprarently if the glyph is really larger
  14134. // than our metrics, it won't render. This happens with foreign characters where we think its 28
  14135. // wide, it's actually 34 (by XuiMeasureText numbers), we snap to 32, glyph gets culled.
  14136. // The downside to this is we have bad metrics and we may be clipping bottom and right.
  14137. rtWidth = AlignValue( rtWidth, 64 );
  14138. rtHeight = AlignValue( rtHeight, 64 );
  14139. // create a render target to capture the glyph render
  14140. pRTSurface = g_TextureHeap.AllocRenderTargetSurface( rtWidth, rtHeight, D3DFMT_A8R8G8B8 );
  14141. if ( !pRTSurface )
  14142. goto cleanUp;
  14143. Dx9Device()->SetRenderTarget( 0, pRTSurface );
  14144. // Disable depth here otherwise you get a colour/depth multisample mismatch error (in 480p)
  14145. Dx9Device()->SetDepthStencilSurface( NULL );
  14146. Dx9Device()->Clear( 0, NULL, D3DCLEAR_TARGET, 0x00000000, ( ReverseDepthOnX360() ? 0.0 : 1.0f ), 0 );
  14147. // create texture to get glyph render from EDRAM
  14148. HRESULT hr = Dx9Device()->CreateTexture( rtWidth, rtHeight, 1, 0, D3DFMT_A8R8G8B8, 0, &pTexture, NULL );
  14149. if ( FAILED( hr ) )
  14150. goto cleanUp;
  14151. XuiRenderBegin( m_hDC, 0x00000000 );
  14152. D3DXMatrixIdentity( &matView );
  14153. XuiRenderSetViewTransform( m_hDC, &matView );
  14154. XuiRenderSetTransform( m_hDC, &matView );
  14155. // rasterize the glyph
  14156. XuiSelectFont( m_hDC, hFont );
  14157. XuiSetColorFactor( m_hDC, 0xFFFFFFFF );
  14158. // Draw the characters, stepping across the texture
  14159. int xCursor = 0;
  14160. for ( int i = 0; i < numChars; i++)
  14161. {
  14162. // FIXME: the drawRect params don't make much sense (should use "(xCursor+pWidth[i]), pHeight[i]", but then some characters disappear!)
  14163. XUIRect drawRect = XUIRect( xCursor + pOffsetX[i], pOffsetY[i], rtWidth, rtHeight );
  14164. wchar_t text[2] = { pWch[i], 0 };
  14165. XuiDrawText( m_hDC, text, XUI_FONT_STYLE_NORMAL|XUI_FONT_STYLE_SINGLE_LINE|XUI_FONT_STYLE_NO_WORDWRAP, 0, &drawRect );
  14166. xCursor += pWidth[i];
  14167. }
  14168. XuiRenderEnd( m_hDC );
  14169. // transfer from edram to system
  14170. hr = Dx9Device()->Resolve( 0, NULL, pTexture, NULL, 0, 0, NULL, 0, 0, NULL );
  14171. if ( FAILED( hr ) )
  14172. goto cleanUp;
  14173. hr = pTexture->LockRect( 0, &lockedRect, NULL, 0 );
  14174. if ( FAILED( hr ) )
  14175. goto cleanUp;
  14176. // transfer to linear format, one character at a time
  14177. xCursor = 0;
  14178. for ( int i = 0;i < numChars; i++ )
  14179. {
  14180. int destPitch = pWidth[i]*4;
  14181. unsigned char *pLinear = pRGBA + pRGBAOffset[i];
  14182. RECT copyRect = { xCursor, 0, xCursor + pWidth[i], pHeight[i] };
  14183. xCursor += pWidth[i];
  14184. XGUntileSurface( pLinear, destPitch, NULL, lockedRect.pBits, rtWidth, rtHeight, &copyRect, 4 );
  14185. // convert argb to rgba
  14186. float r, g, b, a;
  14187. for ( int y = 0; y < pHeight[i]; y++ )
  14188. {
  14189. unsigned char *pSrc = (unsigned char*)pLinear + y*destPitch;
  14190. for ( int x = 0; x < pWidth[i]; x++ )
  14191. {
  14192. // undo pre-multiplied alpha since glyph bits will be sourced as a rgba texture
  14193. if ( !pSrc[0] )
  14194. a = 1;
  14195. else
  14196. a = (float)pSrc[0] * 1.0f/255.0f;
  14197. r = ((float)pSrc[1] * 1.0f/255.0f)/a * 255.0f;
  14198. if ( r > 255 )
  14199. r = 255;
  14200. g = ((float)pSrc[2] * 1.0f/255.0f)/a * 255.0f;
  14201. if ( g > 255 )
  14202. g = 255;
  14203. b = ((float)pSrc[3] * 1.0f/255.0f)/a * 255.0f;
  14204. if ( b > 255 )
  14205. b = 255;
  14206. pSrc[3] = pSrc[0];
  14207. pSrc[2] = b;
  14208. pSrc[1] = g;
  14209. pSrc[0] = r;
  14210. pSrc += 4;
  14211. }
  14212. }
  14213. }
  14214. pTexture->UnlockRect( 0 );
  14215. bSuccess = true;
  14216. cleanUp:
  14217. if ( pRTSurface )
  14218. {
  14219. Dx9Device()->SetRenderTarget( 0, pSavedSurface );
  14220. Dx9Device()->SetDepthStencilSurface( pSavedDepthSurface );
  14221. Dx9Device()->SetViewport( &savedViewport );
  14222. pRTSurface->Release();
  14223. }
  14224. if ( pTexture )
  14225. pTexture->Release();
  14226. if ( pSavedSurface )
  14227. pSavedSurface->Release();
  14228. // XUI changed renderstates behind our back, so we need to reset to defaults again to get matching states
  14229. ResetRenderState( false );
  14230. OwnGPUResources( bPreviousOwnState );
  14231. return bSuccess;
  14232. }
  14233. #endif
  14234. //-----------------------------------------------------------------------------
  14235. // Create a 360 Render Target Surface
  14236. //-----------------------------------------------------------------------------
  14237. #if defined( _X360 )
  14238. ShaderAPITextureHandle_t CShaderAPIDx8::CreateRenderTargetSurface( int width, int height, ImageFormat format, RTMultiSampleCount360_t multiSampleCount, const char *pDebugName, const char *pTextureGroupName )
  14239. {
  14240. LOCK_SHADERAPI();
  14241. ShaderAPITextureHandle_t textureHandle = CreateTextureHandle();
  14242. Texture_t *pTexture = &GetTexture( textureHandle );
  14243. pTexture->m_Flags = (Texture_t::IS_ALLOCATED | Texture_t::IS_RENDER_TARGET_SURFACE);
  14244. pTexture->m_CreationFlags = 0;
  14245. pTexture->m_DebugName = pDebugName;
  14246. pTexture->m_Width = width;
  14247. pTexture->m_Height = height;
  14248. pTexture->m_Depth = 1;
  14249. pTexture->m_NumCopies = 1;
  14250. pTexture->m_CurrentCopy = 0;
  14251. D3DFORMAT actualFormat = FindNearestSupportedFormat( format, false, true, false );
  14252. ImageFormat dstImageFormat = ImageLoader::D3DFormatToImageFormat( actualFormat );
  14253. pTexture->GetRenderTargetSurface( false ) = g_TextureHeap.AllocRenderTargetSurface( width, height, actualFormat, multiSampleCount );
  14254. #if defined( CSTRIKE15 )
  14255. // [mariod] - implicit srgb render targets (regular 8888, writes happen in shaders) as opposed to PWL
  14256. pTexture->GetRenderTargetSurface( true ) = g_TextureHeap.AllocRenderTargetSurface( width, height, actualFormat, multiSampleCount );
  14257. #else
  14258. pTexture->GetRenderTargetSurface( true ) = g_TextureHeap.AllocRenderTargetSurface( width, height, (D3DFORMAT)MAKESRGBFMT( actualFormat ), multiSampleCount );
  14259. #endif
  14260. pTexture->SetImageFormat( dstImageFormat );
  14261. pTexture->m_UTexWrap = D3DTADDRESS_CLAMP;
  14262. pTexture->m_VTexWrap = D3DTADDRESS_CLAMP;
  14263. pTexture->m_WTexWrap = D3DTADDRESS_CLAMP;
  14264. pTexture->m_MagFilter = D3DTEXF_LINEAR;
  14265. pTexture->m_NumLevels = 1;
  14266. pTexture->m_MipFilter = D3DTEXF_NONE;
  14267. pTexture->m_MinFilter = D3DTEXF_LINEAR;
  14268. pTexture->m_SwitchNeeded = false;
  14269. ComputeStatsInfo( textureHandle, false, false );
  14270. SetupTextureGroup( textureHandle, pTextureGroupName );
  14271. return textureHandle;
  14272. }
  14273. #endif
  14274. //-----------------------------------------------------------------------------
  14275. // Shader constants are batched and written to gpu once prior to draw.
  14276. //-----------------------------------------------------------------------------
  14277. void CShaderAPIDx8::WriteShaderConstantsToGPU()
  14278. {
  14279. #if defined( _X360 )
  14280. if ( !IsGPUOwnSupported() || !m_bGPUOwned )
  14281. {
  14282. return;
  14283. }
  14284. // vector vertex constants can just blast their set range
  14285. if ( m_MaxVectorVertexShaderConstant )
  14286. {
  14287. if ( m_bGPUOwned )
  14288. {
  14289. // faster path, write directly into GPU command buffer, bypassing shadow state
  14290. // can only set what is actually owned
  14291. Assert( m_MaxVectorVertexShaderConstant <= VERTEX_SHADER_MODEL + 3*NUM_MODEL_TRANSFORMS );
  14292. int numVectors = AlignValue( m_MaxVectorVertexShaderConstant, 4 );
  14293. BYTE* pCommandBufferData;
  14294. Dx9Device()->GpuBeginVertexShaderConstantF4( 0, (D3DVECTOR4**)&pCommandBufferData, numVectors );
  14295. memcpy( pCommandBufferData, m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), numVectors * (sizeof( float ) * 4) );
  14296. Dx9Device()->GpuEndVertexShaderConstantF4();
  14297. }
  14298. else
  14299. {
  14300. Dx9Device()->SetVertexShaderConstantF( 0, m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), m_MaxVectorVertexShaderConstant );
  14301. }
  14302. memcpy( m_DynamicState.m_pVectorVertexShaderConstant[0].Base(), m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), m_MaxVectorVertexShaderConstant * 4 * sizeof(float) );
  14303. m_MaxVectorVertexShaderConstant = 0;
  14304. }
  14305. if ( m_MaxVectorPixelShaderConstant )
  14306. {
  14307. if ( m_bGPUOwned )
  14308. {
  14309. // faster path, write directly into GPU command buffer, bypassing shadow state
  14310. // can only set what is actually owned
  14311. Assert( m_MaxVectorPixelShaderConstant <= 32 );
  14312. int numVectors = AlignValue( m_MaxVectorPixelShaderConstant, 4 );
  14313. BYTE* pCommandBufferData;
  14314. Dx9Device()->GpuBeginPixelShaderConstantF4( 0, (D3DVECTOR4**)&pCommandBufferData, numVectors );
  14315. memcpy( pCommandBufferData, m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), numVectors * (sizeof( float ) * 4) );
  14316. Dx9Device()->GpuEndPixelShaderConstantF4();
  14317. }
  14318. else
  14319. {
  14320. Dx9Device()->SetPixelShaderConstantF( 0, m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), m_MaxVectorPixelShaderConstant );
  14321. }
  14322. memcpy( m_DynamicState.m_pVectorPixelShaderConstant[0].Base(), m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), m_MaxVectorPixelShaderConstant * 4 * sizeof(float) );
  14323. m_MaxVectorPixelShaderConstant = 0;
  14324. }
  14325. // boolean and integer constants can just blast their set range
  14326. // these are currently extremely small in number, if this changes they may benefit from a fast path pattern
  14327. if ( m_MaxBooleanVertexShaderConstant )
  14328. {
  14329. Dx9Device()->SetVertexShaderConstantB( 0, m_DesiredState.m_pBooleanVertexShaderConstant, m_MaxBooleanVertexShaderConstant );
  14330. memcpy( m_DynamicState.m_pBooleanVertexShaderConstant, m_DesiredState.m_pBooleanVertexShaderConstant, m_MaxBooleanVertexShaderConstant * sizeof(BOOL) );
  14331. m_MaxBooleanVertexShaderConstant = 0;
  14332. }
  14333. if ( m_MaxIntegerVertexShaderConstant )
  14334. {
  14335. Dx9Device()->SetVertexShaderConstantI( 0, (int *)m_DesiredState.m_pIntegerVertexShaderConstant, m_MaxIntegerVertexShaderConstant );
  14336. memcpy( m_DynamicState.m_pIntegerVertexShaderConstant[0].Base(), m_DesiredState.m_pIntegerVertexShaderConstant[0].Base(), m_MaxIntegerVertexShaderConstant * sizeof(IntVector4D) );
  14337. m_MaxIntegerVertexShaderConstant = 0;
  14338. }
  14339. if ( m_MaxBooleanPixelShaderConstant )
  14340. {
  14341. Dx9Device()->SetPixelShaderConstantB( 0, m_DesiredState.m_pBooleanPixelShaderConstant, m_MaxBooleanPixelShaderConstant );
  14342. memcpy( m_DynamicState.m_pBooleanPixelShaderConstant, m_DesiredState.m_pBooleanPixelShaderConstant, m_MaxBooleanPixelShaderConstant * sizeof(BOOL) );
  14343. m_MaxBooleanPixelShaderConstant = 0;
  14344. }
  14345. // integer pixel constants are not used, so not supporting
  14346. #if 0
  14347. if ( m_MaxIntegerPixelShaderConstant )
  14348. {
  14349. Dx9Device()->SetPixelShaderConstantI( 0, (int *)m_DesiredState.m_pIntegerPixelShaderConstant, m_MaxIntegerPixelShaderConstant );
  14350. memcpy( m_DynamicState.m_pIntegerPixelShaderConstant[0].Base(), m_DesiredState.m_pIntegerPixelShaderConstant[0].Base(), m_MaxIntegerPixelShaderConstant * sizeof(IntVector4D) );
  14351. m_MaxIntegerPixelShaderConstant = 0;
  14352. }
  14353. #endif
  14354. #endif
  14355. }
  14356. //-----------------------------------------------------------------------------
  14357. // The application is about to perform a hard reboot, but wants to hide the screen flash
  14358. // by persisting the front buffer across a reboot boundary. The persisted frame buffer
  14359. // can be detected and restored.
  14360. //-----------------------------------------------------------------------------
  14361. #if defined( _X360 )
  14362. void CShaderAPIDx8::PersistDisplay()
  14363. {
  14364. if ( m_PresentParameters.FrontBufferFormat != D3DFMT_LE_X8R8G8B8 )
  14365. {
  14366. // The format must be what PersistDisplay() expects, otherwise D3DRIP.
  14367. // If this hits due to sRGB bit set that confuses PersistDisplay(),
  14368. // the fix may be to slam the presentation parameters to the expected format,
  14369. // do a ResetDevice(), and then PersistDisplay().
  14370. Assert( 0 );
  14371. return;
  14372. }
  14373. IDirect3DTexture *pTexture;
  14374. HRESULT hr = Dx9Device()->GetFrontBuffer( &pTexture );
  14375. if ( !FAILED( hr ) )
  14376. {
  14377. OwnGPUResources( false );
  14378. Dx9Device()->PersistDisplay( pTexture, NULL );
  14379. pTexture->Release();
  14380. }
  14381. }
  14382. #endif
  14383. #if defined( _GAMECONSOLE )
  14384. bool CShaderAPIDx8::PostQueuedTexture( const void *pData, int nDataSize, ShaderAPITextureHandle_t *pHandles, int numHandles, int nWidth, int nHeight, int nDepth, int numMips, int *pRefCount )
  14385. {
  14386. CUtlBuffer vtfBuffer;
  14387. IVTFTexture *pVTFTexture = NULL;
  14388. int iTopMip = 0;
  14389. bool bOK = false;
  14390. if ( !pData || !nDataSize )
  14391. {
  14392. // invalid
  14393. goto cleanUp;
  14394. }
  14395. // get a unique vtf and mount texture
  14396. // vtf can expect non-volatile buffer data to be stable through vtf lifetime
  14397. // this prevents redundant copious amounts of image memory transfers
  14398. pVTFTexture = CreateVTFTexture();
  14399. vtfBuffer.SetExternalBuffer( (void *)pData, nDataSize, nDataSize );
  14400. if ( !pVTFTexture->UnserializeFromBuffer( vtfBuffer, false, false, false, 0 ) )
  14401. {
  14402. goto cleanUp;
  14403. }
  14404. // provided vtf buffer is all mips, determine top mip due to possible picmip
  14405. int mipWidth, mipHeight, mipDepth;
  14406. do
  14407. {
  14408. pVTFTexture->ComputeMipLevelDimensions( iTopMip, &mipWidth, &mipHeight, &mipDepth );
  14409. if ( nWidth == mipWidth && nHeight == mipHeight && nDepth == mipDepth )
  14410. {
  14411. break;
  14412. }
  14413. iTopMip++;
  14414. }
  14415. while ( mipWidth != 1 || mipHeight != 1 || mipDepth != 1 );
  14416. // create and blit
  14417. for ( int iFrame = 0; iFrame < numHandles; iFrame++ )
  14418. {
  14419. ShaderAPITextureHandle_t hTexture = pHandles[iFrame];
  14420. Texture_t *pTexture = &GetTexture( hTexture );
  14421. int nFaceCount = ( pTexture->m_CreationFlags & TEXTURE_CREATE_CUBEMAP ) ? CUBEMAP_FACE_COUNT : 1;
  14422. IDirect3DBaseTexture *pD3DTexture;
  14423. if ( pTexture->m_CreationFlags & TEXTURE_CREATE_NOD3DMEMORY )
  14424. {
  14425. // We created the texture, but deferred allocating storage for the bits until now
  14426. pD3DTexture = pTexture->GetTexture();
  14427. #if defined( _X360 )
  14428. if ( !g_TextureHeap.FixupAllocD3DMemory( pD3DTexture ) )
  14429. {
  14430. goto cleanUp;
  14431. }
  14432. #elif defined( _PS3 )
  14433. if ( !Dx9Device()->AllocateTextureStorage( pD3DTexture ) )
  14434. {
  14435. goto cleanUp;
  14436. }
  14437. #endif // _X360/_PS3
  14438. }
  14439. else
  14440. {
  14441. pD3DTexture = pTexture->GetTexture();
  14442. }
  14443. // blit the hi-res texture bits into d3d memory
  14444. for ( int iFace = 0; iFace < nFaceCount; ++iFace )
  14445. {
  14446. for ( int iMip = 0; iMip < numMips; ++iMip )
  14447. {
  14448. pVTFTexture->ComputeMipLevelDimensions( iTopMip + iMip, &mipWidth, &mipHeight, &mipDepth );
  14449. unsigned char *pSourceBits = pVTFTexture->ImageData( iFrame, iFace, iTopMip + iMip, 0, 0, 0 );
  14450. TextureLoadInfo_t info;
  14451. info.m_TextureHandle = hTexture;
  14452. info.m_pTexture = pD3DTexture;
  14453. info.m_nLevel = iMip;
  14454. info.m_nCopy = 0;
  14455. info.m_CubeFaceID = (D3DCUBEMAP_FACES)iFace;
  14456. info.m_nWidth = mipWidth;
  14457. info.m_nHeight = mipHeight;
  14458. info.m_nZOffset = 0;
  14459. info.m_SrcFormat = pVTFTexture->Format();
  14460. info.m_pSrcData = pSourceBits;
  14461. #if defined( _X360 )
  14462. info.m_bSrcIsTiled = pVTFTexture->IsPreTiled();
  14463. info.m_bCanConvertFormat = ( pTexture->m_Flags & Texture_t::CAN_CONVERT_FORMAT ) != 0;
  14464. #endif // _X360
  14465. LoadTexture( info );
  14466. }
  14467. }
  14468. pTexture->m_Flags |= Texture_t::IS_FINALIZED;
  14469. (*pRefCount)--;
  14470. }
  14471. // success
  14472. bOK = true;
  14473. cleanUp:
  14474. if ( pVTFTexture )
  14475. {
  14476. DestroyVTFTexture( pVTFTexture );
  14477. }
  14478. if ( !bOK )
  14479. {
  14480. // undo artificial lock
  14481. (*pRefCount) -= numHandles;
  14482. }
  14483. return bOK;
  14484. }
  14485. #endif
  14486. #if defined( _X360 )
  14487. void CShaderAPIDx8::SetCacheableTextureParams( ShaderAPITextureHandle_t *pHandles, int count, const char *pFilename, int mipSkipCount )
  14488. {
  14489. for ( int i = 0; i < count; i++ )
  14490. {
  14491. Texture_t *pTexture = &GetTexture( pHandles[i] );
  14492. if ( !( pTexture->m_Flags & Texture_t::IS_CACHEABLE ) )
  14493. {
  14494. // ignore
  14495. continue;
  14496. }
  14497. g_TextureHeap.SetCacheableTextureParams( pTexture->GetTexture(), pFilename, mipSkipCount );
  14498. }
  14499. }
  14500. #endif
  14501. #if defined( _X360 )
  14502. void *CShaderAPIDx8::GetD3DDevice()
  14503. {
  14504. return Dx9Device();
  14505. }
  14506. #endif
  14507. #if defined( _X360 )
  14508. static void r_enable_gpr_allocations_callback( IConVar *var, const char *pOldValue, float flOldValue )
  14509. {
  14510. if ( ((ConVar *)var)->GetBool() == false )
  14511. {
  14512. //reset back the default 64/64 allocation before we stop updating
  14513. if( Dx9Device() != NULL )
  14514. {
  14515. Dx9Device()->SetShaderGPRAllocation( 0, 0, 0 );
  14516. }
  14517. }
  14518. }
  14519. ConVar r_enable_gpr_allocations( "r_enable_gpr_allocations", "1", 0, "Enable usage of IDirect3DDevice9::SetShaderGPRAllocation()", r_enable_gpr_allocations_callback );
  14520. static void CommitShaderGPRs( D3DDeviceWrapper *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce )
  14521. {
  14522. if ( ( desiredState.m_iVertexShaderGPRAllocation != currentState.m_iVertexShaderGPRAllocation ) || bForce )
  14523. {
  14524. if ( pDevice->GetDeviceState() & D3DDEVICESTATE_ZPASS_BRACKET )
  14525. {
  14526. // if a z pass is active, we need to predicate the allocation to only happen in the main render pass
  14527. pDevice->SetPredication( D3DPRED_ALL_RENDER );
  14528. pDevice->SetShaderGPRAllocation( D3DSETALLOCATION_PREDICATED, desiredState.m_iVertexShaderGPRAllocation, 128 - desiredState.m_iVertexShaderGPRAllocation );
  14529. pDevice->SetPredication( 0 );
  14530. }
  14531. else
  14532. {
  14533. pDevice->SetShaderGPRAllocation( 0, desiredState.m_iVertexShaderGPRAllocation, 128 - desiredState.m_iVertexShaderGPRAllocation );
  14534. }
  14535. currentState.m_iVertexShaderGPRAllocation = desiredState.m_iVertexShaderGPRAllocation;
  14536. }
  14537. }
  14538. void CShaderAPIDx8::PushVertexShaderGPRAllocation( int iVertexShaderCount )
  14539. {
  14540. Assert( (iVertexShaderCount >= 16) && (iVertexShaderCount <= 112) );
  14541. m_VertexShaderGPRAllocationStack.Push( iVertexShaderCount );
  14542. if ( r_enable_gpr_allocations.GetBool() )
  14543. {
  14544. if ( m_DesiredState.m_iVertexShaderGPRAllocation != iVertexShaderCount )
  14545. {
  14546. m_DesiredState.m_iVertexShaderGPRAllocation = iVertexShaderCount;
  14547. ADD_COMMIT_FUNC( COMMIT_PER_DRAW, CommitShaderGPRs );
  14548. }
  14549. }
  14550. }
  14551. void CShaderAPIDx8::PopVertexShaderGPRAllocation( void )
  14552. {
  14553. m_VertexShaderGPRAllocationStack.Pop();
  14554. if ( r_enable_gpr_allocations.GetBool() )
  14555. {
  14556. int iVertexShaderCount;
  14557. if ( m_VertexShaderGPRAllocationStack.Count() )
  14558. iVertexShaderCount = m_VertexShaderGPRAllocationStack.Top();
  14559. else
  14560. iVertexShaderCount = 64;
  14561. if ( m_DesiredState.m_iVertexShaderGPRAllocation != iVertexShaderCount )
  14562. {
  14563. m_DesiredState.m_iVertexShaderGPRAllocation = iVertexShaderCount;
  14564. ADD_COMMIT_FUNC( COMMIT_PER_DRAW, CommitShaderGPRs );
  14565. }
  14566. }
  14567. }
  14568. void CShaderAPIDx8::EnableVSync_360( bool bEnable )
  14569. {
  14570. if ( bEnable )
  14571. {
  14572. Dx9Device()->SetRenderState( D3DRS_PRESENTIMMEDIATETHRESHOLD, mat_x360_vblank_miss_threshold.GetInt() ); //only swap on vertical blanks
  14573. }
  14574. else
  14575. {
  14576. Dx9Device()->SetRenderState( D3DRS_PRESENTIMMEDIATETHRESHOLD, 100 ); //allow a swap at any point in the DAC scan
  14577. }
  14578. }
  14579. #endif
  14580. // ------------ New Vertex/Index Buffer interface ----------------------------
  14581. void CShaderAPIDx8::BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions )
  14582. {
  14583. LOCK_SHADERAPI();
  14584. MeshMgr()->BindVertexBuffer( streamID, pVertexBuffer, nOffsetInBytes, nFirstVertex, nVertexCount, fmt, nRepetitions );
  14585. }
  14586. void CShaderAPIDx8::BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes )
  14587. {
  14588. LOCK_SHADERAPI();
  14589. MeshMgr()->BindIndexBuffer( pIndexBuffer, nOffsetInBytes );
  14590. }
  14591. void CShaderAPIDx8::Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount )
  14592. {
  14593. LOCK_SHADERAPI();
  14594. MeshMgr()->Draw( primitiveType, nFirstIndex, nIndexCount );
  14595. }
  14596. // ------------ End ----------------------------
  14597. float CShaderAPIDx8::GammaToLinear_HardwareSpecific( float fGamma ) const
  14598. {
  14599. return SrgbGammaToLinear( fGamma );
  14600. }
  14601. float CShaderAPIDx8::LinearToGamma_HardwareSpecific( float fLinear ) const
  14602. {
  14603. return SrgbLinearToGamma( fLinear );
  14604. }
  14605. bool CShaderAPIDx8::ShouldWriteDepthToDestAlpha( void ) const
  14606. {
  14607. return IsPC() && g_pHardwareConfig->GetDXSupportLevel() >= 92 &&
  14608. (m_SceneFogMode != MATERIAL_FOG_LINEAR_BELOW_FOG_Z) &&
  14609. (GetIntRenderingParameter(INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA) != 0);
  14610. }
  14611. //-----------------------------------------------------------------------------
  14612. //-----------------------------------------------------------------------------
  14613. void CShaderAPIDx8::AcquireThreadOwnership()
  14614. {
  14615. SetCurrentThreadAsOwner();
  14616. #if defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION )
  14617. Dx9Device()->AcquireThreadOwnership();
  14618. #endif
  14619. }
  14620. //-----------------------------------------------------------------------------
  14621. //-----------------------------------------------------------------------------
  14622. void CShaderAPIDx8::ReleaseThreadOwnership()
  14623. {
  14624. RemoveThreadOwner();
  14625. #if defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION )
  14626. Dx9Device()->ReleaseThreadOwnership();
  14627. #endif
  14628. }
  14629. //-----------------------------------------------------------------------------
  14630. // Actual low level setting of the color RT. All Xbox RT funnels here
  14631. // to track the actual RT state. Returns true if the RT gets set, otherwise false.
  14632. //-----------------------------------------------------------------------------
  14633. bool CShaderAPIDx8::SetRenderTargetInternalXbox( ShaderAPITextureHandle_t hRenderTargetTexture, bool bForce )
  14634. {
  14635. // valid for 360 only
  14636. if ( IsPC() )
  14637. {
  14638. Assert( 0 );
  14639. return false;
  14640. }
  14641. if ( hRenderTargetTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
  14642. {
  14643. // could be a reset, force to back buffer
  14644. hRenderTargetTexture = SHADER_RENDERTARGET_BACKBUFFER;
  14645. }
  14646. if ( m_hCachedRenderTarget == INVALID_SHADERAPI_TEXTURE_HANDLE )
  14647. {
  14648. // let the set go through to establish the initial state
  14649. bForce = true;
  14650. }
  14651. if ( !bForce && ( hRenderTargetTexture == m_hCachedRenderTarget && m_DynamicState.m_bSRGBWritesEnabled == m_bUsingSRGBRenderTarget ) )
  14652. {
  14653. // current RT matches expected state, leave state intact
  14654. return false;
  14655. }
  14656. // track the updated state
  14657. m_bUsingSRGBRenderTarget = m_DynamicState.m_bSRGBWritesEnabled;
  14658. m_hCachedRenderTarget = hRenderTargetTexture;
  14659. #if defined( _X360 )
  14660. IDirect3DSurface *pSurface;
  14661. if ( m_hCachedRenderTarget == SHADER_RENDERTARGET_BACKBUFFER )
  14662. {
  14663. if ( !m_bUsingSRGBRenderTarget )
  14664. {
  14665. pSurface = m_pBackBufferSurfaces[BACK_BUFFER_INDEX_DEFAULT];
  14666. }
  14667. else
  14668. {
  14669. pSurface = m_pBackBufferSurfaceSRGB;
  14670. }
  14671. }
  14672. else
  14673. {
  14674. AssertValidTextureHandle( m_hCachedRenderTarget );
  14675. Texture_t *pTexture = &GetTexture( m_hCachedRenderTarget );
  14676. pSurface = pTexture->GetRenderTargetSurface( m_bUsingSRGBRenderTarget );
  14677. }
  14678. // the 360 does a wierd reset of some states on a SetRenderTarget()
  14679. // the viewport is a clobbered state, it may not be changed by later callers, so it MUST be put back as expected
  14680. // the other clobbered states are waiting to be discovered ... sigh
  14681. D3DVIEWPORT9 viewport;
  14682. Dx9Device()->GetViewport( &viewport );
  14683. Dx9Device()->SetRenderTarget( 0, pSurface );
  14684. Dx9Device()->SetViewport( &viewport );
  14685. #endif
  14686. return true;
  14687. }
  14688. void CShaderAPIDx8::OnPresent( void )
  14689. {
  14690. CallCommitFuncs( COMMIT_PER_DRAW );
  14691. }
  14692. void CShaderAPIDx8::AddShaderComboInformation( const ShaderComboSemantics_t *pSemantics )
  14693. {
  14694. ShaderManager()->AddShaderComboInformation( pSemantics );
  14695. }
  14696. //-----------------------------------------------------------------------------
  14697. // debug logging
  14698. //-----------------------------------------------------------------------------
  14699. void CShaderAPIDx8::PrintfVA( char *fmt, va_list vargs )
  14700. {
  14701. #ifdef DX_TO_GL_ABSTRACTION
  14702. #if GLMDEBUG
  14703. GLMPrintfVA( fmt, vargs );
  14704. #endif
  14705. #else
  14706. AssertOnce( !"Impl me" );
  14707. #endif
  14708. }
  14709. void CShaderAPIDx8::Printf( char *fmt, ... )
  14710. {
  14711. #ifdef DX_TO_GL_ABSTRACTION
  14712. #if GLMDEBUG
  14713. va_list vargs;
  14714. va_start(vargs, fmt);
  14715. GLMPrintfVA( fmt, vargs );
  14716. va_end( vargs );
  14717. #endif
  14718. #else
  14719. AssertOnce( !"Impl me" );
  14720. #endif
  14721. }
  14722. float CShaderAPIDx8::Knob( char *knobname, float *setvalue )
  14723. {
  14724. #ifdef DX_TO_GL_ABSTRACTION
  14725. #if GLMDEBUG
  14726. return GLMKnob( knobname, setvalue );
  14727. #else
  14728. return 0.0f;
  14729. #endif
  14730. #else
  14731. return 0.0f;
  14732. #endif
  14733. }
  14734. float CShaderAPIDx8::GetLightMapScaleFactor() const
  14735. {
  14736. return HardwareConfig()->GetLightMapScaleFactor();
  14737. }
  14738. ShaderAPITextureHandle_t CShaderAPIDx8::FindTexture( const char *pDebugName )
  14739. {
  14740. for ( ShaderAPITextureHandle_t hTexture = m_Textures.Head() ; hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
  14741. {
  14742. Texture_t &tex = m_Textures[hTexture];
  14743. if ( !V_stricmp( tex.m_DebugName.String(), pDebugName ) )
  14744. {
  14745. return hTexture;
  14746. }
  14747. }
  14748. // not found
  14749. return INVALID_SHADERAPI_TEXTURE_HANDLE;
  14750. }
  14751. void CShaderAPIDx8::GetTextureDimensions( ShaderAPITextureHandle_t hTexture, int &nWidth, int &nHeight, int &nDepth )
  14752. {
  14753. nWidth = 0;
  14754. nHeight = 0;
  14755. nDepth = 1;
  14756. if ( hTexture == INVALID_SHADERAPI_TEXTURE_HANDLE || !TextureIsAllocated( hTexture ) )
  14757. return;
  14758. Texture_t *pTexture = &GetTexture( hTexture );
  14759. nWidth = pTexture->m_Width;
  14760. nHeight = pTexture->m_Height;
  14761. nDepth = pTexture->m_Depth;
  14762. }
  14763. #if defined( _X360 )
  14764. extern ConVar r_blocking_spew_threshold;
  14765. void D3DBlockingSpewCallback( DWORD Flags, D3DBLOCKTYPE BlockType, float ClockTime, DWORD ThreadTime )
  14766. {
  14767. if ( ClockTime >= r_blocking_spew_threshold.GetFloat() )
  14768. {
  14769. const char *pBlockType = "";
  14770. switch( BlockType )
  14771. {
  14772. case D3DBLOCKTYPE_NONE:
  14773. pBlockType = "D3DBLOCKTYPE_NONE";
  14774. break;
  14775. case D3DBLOCKTYPE_PRIMARY_OVERRUN:
  14776. pBlockType = "D3DBLOCKTYPE_PRIMARY_OVERRUN";
  14777. break;
  14778. case D3DBLOCKTYPE_SECONDARY_OVERRUN:
  14779. pBlockType = "D3DBLOCKTYPE_SECONDARY_OVERRUN";
  14780. break;
  14781. case D3DBLOCKTYPE_SWAP_THROTTLE:
  14782. pBlockType = "D3DBLOCKTYPE_SWAP_THROTTLE";
  14783. break;
  14784. case D3DBLOCKTYPE_BLOCK_UNTIL_IDLE:
  14785. pBlockType = "D3DBLOCKTYPE_BLOCK_UNTIL_IDLE";
  14786. break;
  14787. case D3DBLOCKTYPE_BLOCK_UNTIL_NOT_BUSY:
  14788. pBlockType = "D3DBLOCKTYPE_BLOCK_UNTIL_NOT_BUSY";
  14789. break;
  14790. case D3DBLOCKTYPE_BLOCK_ON_FENCE:
  14791. pBlockType = "D3DBLOCKTYPE_BLOCK_ON_FENCE";
  14792. break;
  14793. case D3DBLOCKTYPE_VERTEX_SHADER_RELEASE:
  14794. pBlockType = "D3DBLOCKTYPE_VERTEX_SHADER_RELEASE";
  14795. break;
  14796. case D3DBLOCKTYPE_PIXEL_SHADER_RELEASE:
  14797. pBlockType = "D3DBLOCKTYPE_PIXEL_SHADER_RELEASE";
  14798. break;
  14799. case D3DBLOCKTYPE_VERTEX_BUFFER_RELEASE:
  14800. pBlockType = "D3DBLOCKTYPE_VERTEX_BUFFER_RELEASE";
  14801. break;
  14802. case D3DBLOCKTYPE_VERTEX_BUFFER_LOCK:
  14803. pBlockType = "D3DBLOCKTYPE_VERTEX_BUFFER_LOCK";
  14804. break;
  14805. case D3DBLOCKTYPE_INDEX_BUFFER_RELEASE:
  14806. pBlockType = "D3DBLOCKTYPE_INDEX_BUFFER_RELEASE";
  14807. break;
  14808. case D3DBLOCKTYPE_INDEX_BUFFER_LOCK:
  14809. pBlockType = "D3DBLOCKTYPE_INDEX_BUFFER_LOCK";
  14810. break;
  14811. case D3DBLOCKTYPE_TEXTURE_RELEASE:
  14812. pBlockType = "D3DBLOCKTYPE_TEXTURE_RELEASE";
  14813. break;
  14814. case D3DBLOCKTYPE_TEXTURE_LOCK:
  14815. pBlockType = "D3DBLOCKTYPE_TEXTURE_LOCK";
  14816. break;
  14817. case D3DBLOCKTYPE_COMMAND_BUFFER_RELEASE:
  14818. pBlockType = "D3DBLOCKTYPE_COMMAND_BUFFER_RELEASE";
  14819. break;
  14820. case D3DBLOCKTYPE_COMMAND_BUFFER_LOCK:
  14821. pBlockType = "D3DBLOCKTYPE_COMMAND_BUFFER_LOCK";
  14822. break;
  14823. case D3DBLOCKTYPE_CONSTANT_BUFFER_RELEASE:
  14824. pBlockType = "D3DBLOCKTYPE_CONSTANT_BUFFER_RELEASE";
  14825. break;
  14826. case D3DBLOCKTYPE_CONSTANT_BUFFER_LOCK:
  14827. pBlockType = "D3DBLOCKTYPE_CONSTANT_BUFFER_LOCK";
  14828. break;
  14829. NO_DEFAULT;
  14830. };
  14831. Warning( "D3D Block: %s for %.2f ms\n", pBlockType, ClockTime );
  14832. }
  14833. }
  14834. static void r_blocking_spew_threshold_callback( IConVar *var, const char *pOldValue, float flOldValue )
  14835. {
  14836. if ( Dx9Device() != NULL )
  14837. {
  14838. if ( ((ConVar *)var)->GetFloat() >= 0.0f )
  14839. {
  14840. Dx9Device()->SetBlockCallback( 0, D3DBlockingSpewCallback );
  14841. }
  14842. else
  14843. {
  14844. Dx9Device()->SetBlockCallback( 0, NULL );
  14845. }
  14846. }
  14847. }
  14848. ConVar r_blocking_spew_threshold( "r_blocking_spew_threshold", "-1", 0, "Enable spew of Direct3D Blocks. Specify the minimum blocking time in milliseconds before spewing a warning.", r_blocking_spew_threshold_callback );
  14849. #endif
  14850. #ifdef _PS3
  14851. #include "shaderapidx8_ps3nonvirt.inl"
  14852. #endif