Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1545 lines
44 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #define DISABLE_PROTECTED_THINGS
  9. #include "locald3dtypes.h"
  10. #include "texturedx8.h"
  11. #include "shaderapidx8_global.h"
  12. #include "colorformatdx8.h"
  13. #include "shaderapi/ishaderutil.h"
  14. #include "materialsystem/imaterialsystem.h"
  15. #include "utlvector.h"
  16. #include "recording.h"
  17. #include "shaderapi/ishaderapi.h"
  18. #include "filesystem.h"
  19. #include "locald3dtypes.h"
  20. #include "textureheap.h"
  21. #include "tier1/utlbuffer.h"
  22. #include "tier1/callqueue.h"
  23. #include "tier0/vprof.h"
  24. #include "vtf/vtf.h"
  25. #include "tier0/icommandline.h"
  26. #include "tier0/memdbgon.h"
  27. #ifdef _WIN32
  28. #pragma warning (disable:4189 4701)
  29. #endif
  30. static int s_TextureCount = 0;
  31. static bool s_bTestingVideoMemorySize = false;
  32. //-----------------------------------------------------------------------------
  33. // Stats...
  34. //-----------------------------------------------------------------------------
  35. int TextureCount()
  36. {
  37. return s_TextureCount;
  38. }
  39. static bool IsVolumeTexture( IDirect3DBaseTexture* pBaseTexture )
  40. {
  41. if ( !pBaseTexture )
  42. {
  43. return false;
  44. }
  45. return ( pBaseTexture->GetType() == D3DRTYPE_VOLUMETEXTURE );
  46. }
  47. static HRESULT GetLevelDesc( IDirect3DBaseTexture* pBaseTexture, UINT level, D3DSURFACE_DESC* pDesc )
  48. {
  49. MEM_ALLOC_D3D_CREDIT();
  50. if ( !pBaseTexture )
  51. {
  52. return ( HRESULT )-1;
  53. }
  54. HRESULT hr;
  55. switch( pBaseTexture->GetType() )
  56. {
  57. case D3DRTYPE_TEXTURE:
  58. hr = ( ( IDirect3DTexture * )pBaseTexture )->GetLevelDesc( level, pDesc );
  59. break;
  60. case D3DRTYPE_CUBETEXTURE:
  61. hr = ( ( IDirect3DCubeTexture * )pBaseTexture )->GetLevelDesc( level, pDesc );
  62. break;
  63. default:
  64. return ( HRESULT )-1;
  65. }
  66. return hr;
  67. }
  68. static HRESULT GetSurfaceFromTexture( IDirect3DBaseTexture* pBaseTexture, UINT level,
  69. D3DCUBEMAP_FACES cubeFaceID, IDirect3DSurface** ppSurfLevel )
  70. {
  71. MEM_ALLOC_D3D_CREDIT();
  72. if ( !pBaseTexture )
  73. {
  74. return ( HRESULT )-1;
  75. }
  76. HRESULT hr;
  77. switch( pBaseTexture->GetType() )
  78. {
  79. case D3DRTYPE_TEXTURE:
  80. hr = ( ( IDirect3DTexture * )pBaseTexture )->GetSurfaceLevel( level, ppSurfLevel );
  81. break;
  82. case D3DRTYPE_CUBETEXTURE:
  83. if (cubeFaceID !=0)
  84. {
  85. //Debugger();
  86. }
  87. hr = ( ( IDirect3DCubeTexture * )pBaseTexture )->GetCubeMapSurface( cubeFaceID, level, ppSurfLevel );
  88. break;
  89. default:
  90. Assert(0);
  91. return ( HRESULT )-1;
  92. }
  93. return hr;
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Gets the image format of a texture
  97. //-----------------------------------------------------------------------------
  98. static ImageFormat GetImageFormat( IDirect3DBaseTexture* pTexture )
  99. {
  100. MEM_ALLOC_D3D_CREDIT();
  101. if ( pTexture )
  102. {
  103. HRESULT hr;
  104. if ( !IsVolumeTexture( pTexture ) )
  105. {
  106. D3DSURFACE_DESC desc;
  107. hr = GetLevelDesc( pTexture, 0, &desc );
  108. if ( !FAILED( hr ) )
  109. return ImageLoader::D3DFormatToImageFormat( desc.Format );
  110. }
  111. else
  112. {
  113. D3DVOLUME_DESC desc;
  114. IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( pTexture );
  115. hr = pVolumeTexture->GetLevelDesc( 0, &desc );
  116. if ( !FAILED( hr ) )
  117. return ImageLoader::D3DFormatToImageFormat( desc.Format );
  118. }
  119. }
  120. // Bogus baby!
  121. return (ImageFormat)-1;
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Allocates the D3DTexture
  125. //-----------------------------------------------------------------------------
  126. IDirect3DBaseTexture* CreateD3DTexture( int width, int height, int nDepth,
  127. ImageFormat dstFormat, int numLevels, int nCreationFlags, char *debugLabel ) // OK to skip the last param
  128. {
  129. if ( nDepth <= 0 )
  130. {
  131. nDepth = 1;
  132. }
  133. bool isCubeMap = ( nCreationFlags & TEXTURE_CREATE_CUBEMAP ) != 0;
  134. bool bIsRenderTarget = ( nCreationFlags & TEXTURE_CREATE_RENDERTARGET ) != 0;
  135. bool bManaged = ( nCreationFlags & TEXTURE_CREATE_MANAGED ) != 0;
  136. bool bSysmem = ( nCreationFlags & TEXTURE_CREATE_SYSMEM ) != 0;
  137. bool bIsDepthBuffer = ( nCreationFlags & TEXTURE_CREATE_DEPTHBUFFER ) != 0;
  138. bool isDynamic = ( nCreationFlags & TEXTURE_CREATE_DYNAMIC ) != 0;
  139. bool bAutoMipMap = ( nCreationFlags & TEXTURE_CREATE_AUTOMIPMAP ) != 0;
  140. bool bVertexTexture = ( nCreationFlags & TEXTURE_CREATE_VERTEXTEXTURE ) != 0;
  141. bool bAllowNonFilterable = ( nCreationFlags & TEXTURE_CREATE_UNFILTERABLE_OK ) != 0;
  142. bool bVolumeTexture = ( nDepth > 1 );
  143. bool bIsFallback = ( nCreationFlags & TEXTURE_CREATE_FALLBACK ) != 0;
  144. bool bNoD3DBits = ( nCreationFlags & TEXTURE_CREATE_NOD3DMEMORY ) != 0;
  145. bool bSRGB = (nCreationFlags & TEXTURE_CREATE_SRGB) != 0; // for Posix/GL only
  146. // NOTE: This function shouldn't be used for creating depth buffers!
  147. Assert( !bIsDepthBuffer );
  148. D3DFORMAT d3dFormat = D3DFMT_UNKNOWN;
  149. D3DPOOL pool = bManaged ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT;
  150. if ( bSysmem )
  151. pool = D3DPOOL_SYSTEMMEM;
  152. if ( IsX360() )
  153. {
  154. // 360 does not support vertex textures
  155. // 360 render target creation path is for the target as a texture source (NOT the EDRAM version)
  156. // use normal texture format rules
  157. Assert( !bVertexTexture );
  158. if ( !bVertexTexture )
  159. {
  160. d3dFormat = ImageLoader::ImageFormatToD3DFormat( FindNearestSupportedFormat( dstFormat, false, false, false ) );
  161. }
  162. }
  163. else
  164. {
  165. d3dFormat = ImageLoader::ImageFormatToD3DFormat( FindNearestSupportedFormat( dstFormat, bVertexTexture, bIsRenderTarget, bAllowNonFilterable ) );
  166. }
  167. if ( d3dFormat == D3DFMT_UNKNOWN )
  168. {
  169. Warning( "ShaderAPIDX8::CreateD3DTexture: Invalid color format!\n" );
  170. Assert( 0 );
  171. return 0;
  172. }
  173. IDirect3DBaseTexture* pBaseTexture = NULL;
  174. IDirect3DTexture* pD3DTexture = NULL;
  175. IDirect3DCubeTexture* pD3DCubeTexture = NULL;
  176. IDirect3DVolumeTexture* pD3DVolumeTexture = NULL;
  177. HRESULT hr = S_OK;
  178. DWORD usage = 0;
  179. if ( bIsRenderTarget )
  180. {
  181. usage |= D3DUSAGE_RENDERTARGET;
  182. }
  183. if ( isDynamic )
  184. {
  185. usage |= D3DUSAGE_DYNAMIC;
  186. }
  187. if ( bAutoMipMap )
  188. {
  189. usage |= D3DUSAGE_AUTOGENMIPMAP;
  190. }
  191. #ifdef DX_TO_GL_ABSTRACTION
  192. {
  193. if (bSRGB)
  194. {
  195. usage |= D3DUSAGE_TEXTURE_SRGB; // does not exist in real DX9... just for GL to know that this is an SRGB tex
  196. }
  197. }
  198. #endif
  199. if ( isCubeMap )
  200. {
  201. #if !defined( _X360 )
  202. hr = Dx9Device()->CreateCubeTexture(
  203. width,
  204. numLevels,
  205. usage,
  206. d3dFormat,
  207. pool,
  208. &pD3DCubeTexture,
  209. NULL
  210. #if defined( DX_TO_GL_ABSTRACTION )
  211. , debugLabel // tex create funcs take extra arg for debug name on GL
  212. #endif
  213. );
  214. #else
  215. pD3DCubeTexture = g_TextureHeap.AllocCubeTexture( width, numLevels, usage, d3dFormat, bIsFallback, bNoD3DBits );
  216. #endif
  217. pBaseTexture = pD3DCubeTexture;
  218. }
  219. else if ( bVolumeTexture )
  220. {
  221. #if !defined( _X360 )
  222. hr = Dx9Device()->CreateVolumeTexture(
  223. width,
  224. height,
  225. nDepth,
  226. numLevels,
  227. usage,
  228. d3dFormat,
  229. pool,
  230. &pD3DVolumeTexture,
  231. NULL
  232. #if defined( DX_TO_GL_ABSTRACTION )
  233. , debugLabel // tex create funcs take extra arg for debug name on GL
  234. #endif
  235. );
  236. #else
  237. Assert( !bIsFallback && !bNoD3DBits );
  238. pD3DVolumeTexture = g_TextureHeap.AllocVolumeTexture( width, height, nDepth, numLevels, usage, d3dFormat );
  239. #endif
  240. pBaseTexture = pD3DVolumeTexture;
  241. }
  242. else
  243. {
  244. #if !defined( _X360 )
  245. // Override usage and managed params if using special hardware shadow depth map formats...
  246. if ( ( d3dFormat == NVFMT_RAWZ ) || ( d3dFormat == NVFMT_INTZ ) ||
  247. ( d3dFormat == D3DFMT_D16 ) || ( d3dFormat == D3DFMT_D24S8 ) ||
  248. ( d3dFormat == ATIFMT_D16 ) || ( d3dFormat == ATIFMT_D24S8 ) )
  249. {
  250. // Not putting D3DUSAGE_RENDERTARGET here causes D3D debug spew later, but putting the flag causes this create to fail...
  251. usage = D3DUSAGE_DEPTHSTENCIL;
  252. bManaged = false;
  253. }
  254. // Override managed param if using special null texture format
  255. if ( d3dFormat == NVFMT_NULL )
  256. {
  257. bManaged = false;
  258. }
  259. hr = Dx9Device()->CreateTexture(
  260. width,
  261. height,
  262. numLevels,
  263. usage,
  264. d3dFormat,
  265. pool,
  266. &pD3DTexture,
  267. NULL
  268. #if defined( DX_TO_GL_ABSTRACTION )
  269. , debugLabel // tex create funcs take extra arg for debug name on GL
  270. #endif
  271. );
  272. #else
  273. pD3DTexture = g_TextureHeap.AllocTexture( width, height, numLevels, usage, d3dFormat, bIsFallback, bNoD3DBits );
  274. #endif
  275. pBaseTexture = pD3DTexture;
  276. }
  277. if ( FAILED( hr ) )
  278. {
  279. #ifdef ENABLE_NULLREF_DEVICE_SUPPORT
  280. if( CommandLine()->FindParm( "-nulldevice" ) )
  281. {
  282. Warning( "ShaderAPIDX8::CreateD3DTexture: Null device used. Texture not created.\n" );
  283. return 0;
  284. }
  285. #endif
  286. switch ( hr )
  287. {
  288. case D3DERR_INVALIDCALL:
  289. Warning( "ShaderAPIDX8::CreateD3DTexture: D3DERR_INVALIDCALL\n" );
  290. break;
  291. case D3DERR_OUTOFVIDEOMEMORY:
  292. // This conditional is here so that we don't complain when testing
  293. // how much video memory we have. . this is kinda gross.
  294. if ( !s_bTestingVideoMemorySize )
  295. {
  296. Warning( "ShaderAPIDX8::CreateD3DTexture: D3DERR_OUTOFVIDEOMEMORY\n" );
  297. }
  298. break;
  299. case E_OUTOFMEMORY:
  300. Warning( "ShaderAPIDX8::CreateD3DTexture: E_OUTOFMEMORY\n" );
  301. break;
  302. default:
  303. break;
  304. }
  305. return 0;
  306. }
  307. #ifdef MEASURE_DRIVER_ALLOCATIONS
  308. int nMipCount = numLevels;
  309. if ( !nMipCount )
  310. {
  311. while ( width > 1 || height > 1 )
  312. {
  313. width >>= 1;
  314. height >>= 1;
  315. ++nMipCount;
  316. }
  317. }
  318. int nMemUsed = nMipCount * 1.1f * 1024;
  319. if ( isCubeMap )
  320. {
  321. nMemUsed *= 6;
  322. }
  323. VPROF_INCREMENT_GROUP_COUNTER( "texture count", COUNTER_GROUP_NO_RESET, 1 );
  324. VPROF_INCREMENT_GROUP_COUNTER( "texture driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  325. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  326. #endif
  327. ++s_TextureCount;
  328. return pBaseTexture;
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Texture destruction
  332. //-----------------------------------------------------------------------------
  333. void ReleaseD3DTexture( IDirect3DBaseTexture* pD3DTex )
  334. {
  335. int ref = pD3DTex->Release();
  336. Assert( ref == 0 );
  337. }
  338. void DestroyD3DTexture( IDirect3DBaseTexture* pD3DTex )
  339. {
  340. if ( pD3DTex )
  341. {
  342. #ifdef MEASURE_DRIVER_ALLOCATIONS
  343. D3DRESOURCETYPE type = pD3DTex->GetType();
  344. int nMipCount = pD3DTex->GetLevelCount();
  345. if ( type == D3DRTYPE_CUBETEXTURE )
  346. {
  347. nMipCount *= 6;
  348. }
  349. int nMemUsed = nMipCount * 1.1f * 1024;
  350. VPROF_INCREMENT_GROUP_COUNTER( "texture count", COUNTER_GROUP_NO_RESET, -1 );
  351. VPROF_INCREMENT_GROUP_COUNTER( "texture driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  352. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  353. #endif
  354. #if !defined( _X360 )
  355. CMatRenderContextPtr pRenderContext( materials );
  356. ICallQueue *pCallQueue;
  357. if ( ( pCallQueue = pRenderContext->GetCallQueue() ) != NULL )
  358. {
  359. pCallQueue->QueueCall( ReleaseD3DTexture, pD3DTex );
  360. }
  361. else
  362. {
  363. ReleaseD3DTexture( pD3DTex );
  364. }
  365. #else
  366. g_TextureHeap.FreeTexture( pD3DTex );
  367. #endif
  368. --s_TextureCount;
  369. }
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Purpose:
  373. // Input : *pTex -
  374. // Output : int
  375. //-----------------------------------------------------------------------------
  376. int GetD3DTextureRefCount( IDirect3DBaseTexture *pTex )
  377. {
  378. if ( !pTex )
  379. return 0;
  380. pTex->AddRef();
  381. int ref = pTex->Release();
  382. return ref;
  383. }
  384. //-----------------------------------------------------------------------------
  385. // See version 13 for a function that converts a texture to a mipmap (ConvertToMipmap)
  386. //-----------------------------------------------------------------------------
  387. //-----------------------------------------------------------------------------
  388. // Lock, unlock a texture...
  389. //-----------------------------------------------------------------------------
  390. static RECT s_LockedSrcRect;
  391. static D3DLOCKED_RECT s_LockedRect;
  392. #ifdef DBGFLAG_ASSERT
  393. static bool s_bInLock = false;
  394. #endif
  395. bool LockTexture( ShaderAPITextureHandle_t bindId, int copy, IDirect3DBaseTexture* pTexture, int level,
  396. D3DCUBEMAP_FACES cubeFaceID, int xOffset, int yOffset, int width, int height, bool bDiscard,
  397. CPixelWriter& writer )
  398. {
  399. Assert( !s_bInLock );
  400. IDirect3DSurface* pSurf;
  401. HRESULT hr = GetSurfaceFromTexture( pTexture, level, cubeFaceID, &pSurf );
  402. if ( FAILED( hr ) )
  403. return false;
  404. s_LockedSrcRect.left = xOffset;
  405. s_LockedSrcRect.right = xOffset + width;
  406. s_LockedSrcRect.top = yOffset;
  407. s_LockedSrcRect.bottom = yOffset + height;
  408. unsigned int flags = D3DLOCK_NOSYSLOCK;
  409. flags |= bDiscard ? D3DLOCK_DISCARD : 0;
  410. RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
  411. RECORD_INT( bindId );
  412. RECORD_INT( copy );
  413. RECORD_INT( level );
  414. RECORD_INT( cubeFaceID );
  415. RECORD_STRUCT( &s_LockedSrcRect, sizeof(s_LockedSrcRect) );
  416. RECORD_INT( flags );
  417. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "D3DLockTexture" );
  418. hr = pSurf->LockRect( &s_LockedRect, &s_LockedSrcRect, flags );
  419. pSurf->Release();
  420. if ( FAILED( hr ) )
  421. return false;
  422. writer.SetPixelMemory( GetImageFormat(pTexture), s_LockedRect.pBits, s_LockedRect.Pitch );
  423. #ifdef DBGFLAG_ASSERT
  424. s_bInLock = true;
  425. #endif
  426. return true;
  427. }
  428. void UnlockTexture( ShaderAPITextureHandle_t bindId, int copy, IDirect3DBaseTexture* pTexture, int level,
  429. D3DCUBEMAP_FACES cubeFaceID )
  430. {
  431. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  432. Assert( s_bInLock );
  433. IDirect3DSurface* pSurf;
  434. HRESULT hr = GetSurfaceFromTexture( pTexture, level, cubeFaceID, &pSurf );
  435. if (FAILED(hr))
  436. return;
  437. #ifdef RECORD_TEXTURES
  438. int width = s_LockedSrcRect.right - s_LockedSrcRect.left;
  439. int height = s_LockedSrcRect.bottom - s_LockedSrcRect.top;
  440. int imageFormatSize = ImageLoader::SizeInBytes( GetImageFormat( pTexture ) );
  441. Assert( imageFormatSize != 0 );
  442. int validDataBytesPerRow = imageFormatSize * width;
  443. int storeSize = validDataBytesPerRow * height;
  444. static CUtlVector< unsigned char > tmpMem;
  445. if( tmpMem.Size() < storeSize )
  446. {
  447. tmpMem.AddMultipleToTail( storeSize - tmpMem.Size() );
  448. }
  449. unsigned char *pDst = tmpMem.Base();
  450. unsigned char *pSrc = ( unsigned char * )s_LockedRect.pBits;
  451. RECORD_COMMAND( DX8_SET_TEXTURE_DATA, 3 );
  452. RECORD_INT( validDataBytesPerRow );
  453. RECORD_INT( height );
  454. int i;
  455. for( i = 0; i < height; i++ )
  456. {
  457. memcpy( pDst, pSrc, validDataBytesPerRow );
  458. pDst += validDataBytesPerRow;
  459. pSrc += s_LockedRect.Pitch;
  460. }
  461. RECORD_STRUCT( tmpMem.Base(), storeSize );
  462. #endif // RECORD_TEXTURES
  463. RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
  464. RECORD_INT( bindId );
  465. RECORD_INT( copy );
  466. RECORD_INT( level );
  467. RECORD_INT( cubeFaceID );
  468. hr = pSurf->UnlockRect();
  469. pSurf->Release();
  470. #ifdef DBGFLAG_ASSERT
  471. s_bInLock = false;
  472. #endif
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Compute texture size based on compression
  476. //-----------------------------------------------------------------------------
  477. static inline int DetermineGreaterPowerOfTwo( int val )
  478. {
  479. int num = 1;
  480. while (val > num)
  481. {
  482. num <<= 1;
  483. }
  484. return num;
  485. }
  486. inline int DeterminePowerOfTwo( int val )
  487. {
  488. int pow = 0;
  489. while ((val & 0x1) == 0x0)
  490. {
  491. val >>= 1;
  492. ++pow;
  493. }
  494. return pow;
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Blit in bits
  498. //-----------------------------------------------------------------------------
  499. // NOTE: IF YOU CHANGE THIS, CHANGE THE VERSION IN PLAYBACK.CPP!!!!
  500. // OPTIMIZE??: could lock the texture directly instead of the surface in dx9.
  501. #if !defined( _X360 )
  502. static void BlitSurfaceBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  503. {
  504. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  505. // Get the level of the texture we want to write into
  506. IDirect3DSurface* pTextureLevel;
  507. if (info.m_CubeFaceID !=0)
  508. {
  509. //Debugger();
  510. }
  511. HRESULT hr = GetSurfaceFromTexture( info.m_pTexture, info.m_nLevel, info.m_CubeFaceID, &pTextureLevel );
  512. if ( FAILED( hr ) )
  513. return;
  514. RECT srcRect;
  515. RECT *pSrcRect = NULL;
  516. D3DLOCKED_RECT lockedRect;
  517. srcRect.left = xOffset;
  518. srcRect.right = xOffset + info.m_nWidth;
  519. srcRect.top = yOffset;
  520. srcRect.bottom = yOffset + info.m_nHeight;
  521. #if defined( SHADERAPIDX9 ) && !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  522. if ( !info.m_bTextureIsLockable )
  523. {
  524. // Copy from system memory to video memory using D3D9Device->UpdateSurface
  525. bool bSuccess = false;
  526. D3DSURFACE_DESC desc;
  527. Verify( pTextureLevel->GetDesc( &desc ) == S_OK );
  528. ImageFormat dstFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
  529. D3DFORMAT dstFormatD3D = ImageLoader::ImageFormatToD3DFormat( dstFormat );
  530. IDirect3DSurface* pSrcSurface = NULL;
  531. bool bCopyBitsToSrcSurface = true;
  532. #if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
  533. // D3D9Ex fast path: create a texture wrapping our own system memory buffer
  534. // if the source and destination formats are exactly the same and the stride
  535. // is tightly packed. no locking/blitting required.
  536. // NOTE: the fast path does not work on sub-4x4 DXT compressed textures.
  537. extern bool g_ShaderDeviceUsingD3D9Ex;
  538. if ( g_ShaderDeviceUsingD3D9Ex &&
  539. ( info.m_SrcFormat == dstFormat || ( info.m_SrcFormat == IMAGE_FORMAT_DXT1_ONEBITALPHA && dstFormat == IMAGE_FORMAT_DXT1 ) ) &&
  540. ( !ImageLoader::IsCompressed( dstFormat ) || (info.m_nWidth >= 4 || info.m_nHeight >= 4) ) )
  541. {
  542. if ( srcStride == 0 || srcStride == info.m_nWidth * ImageLoader::SizeInBytes( info.m_SrcFormat ) )
  543. {
  544. IDirect3DTexture9* pTempTex = NULL;
  545. if ( Dx9Device()->CreateTexture( info.m_nWidth, info.m_nHeight, 1, 0, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempTex, (HANDLE*) &info.m_pSrcData ) == S_OK )
  546. {
  547. IDirect3DSurface* pTempSurf = NULL;
  548. if ( pTempTex->GetSurfaceLevel( 0, &pTempSurf ) == S_OK )
  549. {
  550. pSrcSurface = pTempSurf;
  551. bCopyBitsToSrcSurface = false;
  552. }
  553. pTempTex->Release();
  554. }
  555. }
  556. }
  557. #endif
  558. // If possible to create a texture of this size, create a temporary texture in
  559. // system memory and then use the UpdateSurface method to copy between textures.
  560. if ( !pSrcSurface && ( g_pHardwareConfig->Caps().m_SupportsNonPow2Textures ||
  561. ( IsPowerOfTwo( info.m_nWidth ) && IsPowerOfTwo( info.m_nHeight ) ) ) )
  562. {
  563. int tempW = info.m_nWidth, tempH = info.m_nHeight, mip = 0;
  564. if ( info.m_nLevel > 0 && ( ( tempW | tempH ) & 3 ) && ImageLoader::IsCompressed( dstFormat ) )
  565. {
  566. // Loading lower mip levels of DXT compressed textures is sort of tricky
  567. // because we can't create textures that aren't multiples of 4, and we can't
  568. // pass subrectangles of DXT textures into UpdateSurface. Create a temporary
  569. // texture which is 1 or 2 mip levels larger and then lock the appropriate
  570. // mip level to grab its correctly-dimensioned surface. -henryg 11/18/2011
  571. mip = ( info.m_nLevel > 1 && ( ( tempW | tempH ) & 1 ) ) ? 2 : 1;
  572. tempW <<= mip;
  573. tempH <<= mip;
  574. }
  575. IDirect3DTexture9* pTempTex = NULL;
  576. IDirect3DSurface* pTempSurf = NULL;
  577. if ( Dx9Device()->CreateTexture( tempW, tempH, mip+1, 0, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempTex, NULL ) == S_OK )
  578. {
  579. if ( pTempTex->GetSurfaceLevel( mip, &pTempSurf ) == S_OK )
  580. {
  581. pSrcSurface = pTempSurf;
  582. bCopyBitsToSrcSurface = true;
  583. }
  584. pTempTex->Release();
  585. }
  586. }
  587. // Create an offscreen surface if the texture path wasn't an option.
  588. if ( !pSrcSurface )
  589. {
  590. IDirect3DSurface* pTempSurf = NULL;
  591. if ( Dx9Device()->CreateOffscreenPlainSurface( info.m_nWidth, info.m_nHeight, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempSurf, NULL ) == S_OK )
  592. {
  593. pSrcSurface = pTempSurf;
  594. bCopyBitsToSrcSurface = true;
  595. }
  596. }
  597. // Lock and fill the surface
  598. if ( bCopyBitsToSrcSurface && pSrcSurface )
  599. {
  600. if ( pSrcSurface->LockRect( &lockedRect, NULL, D3DLOCK_NOSYSLOCK ) == S_OK )
  601. {
  602. unsigned char *pImage = (unsigned char *)lockedRect.pBits;
  603. ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
  604. pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedRect.Pitch );
  605. pSrcSurface->UnlockRect();
  606. }
  607. else
  608. {
  609. // Lock failed.
  610. pSrcSurface->Release();
  611. pSrcSurface = NULL;
  612. }
  613. }
  614. // Perform the UpdateSurface call that blits between system and video memory
  615. if ( pSrcSurface )
  616. {
  617. POINT pt = { xOffset, yOffset };
  618. bSuccess = ( Dx9Device()->UpdateSurface( pSrcSurface, NULL, pTextureLevel, &pt ) == S_OK );
  619. pSrcSurface->Release();
  620. }
  621. if ( !bSuccess )
  622. {
  623. Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect or use UpdateSurface\n" );
  624. }
  625. pTextureLevel->Release();
  626. return;
  627. }
  628. #endif
  629. Assert( info.m_bTextureIsLockable );
  630. #ifndef RECORD_TEXTURES
  631. RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
  632. RECORD_INT( info.m_TextureHandle );
  633. RECORD_INT( info.m_nCopy );
  634. RECORD_INT( info.m_nLevel );
  635. RECORD_INT( info.m_CubeFaceID );
  636. RECORD_STRUCT( &srcRect, sizeof(srcRect) );
  637. RECORD_INT( D3DLOCK_NOSYSLOCK );
  638. #endif
  639. {
  640. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - D3DLockRect", __FUNCTION__ );
  641. // lock the region (could be the full surface or less)
  642. if ( FAILED( pTextureLevel->LockRect( &lockedRect, &srcRect, D3DLOCK_NOSYSLOCK ) ) )
  643. {
  644. Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect\n" );
  645. pTextureLevel->Release();
  646. return;
  647. }
  648. }
  649. {
  650. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - ConvertImageFormat", __FUNCTION__ );
  651. // garymcthack : need to make a recording command for this.
  652. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  653. unsigned char *pImage = (unsigned char *)lockedRect.pBits;
  654. ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
  655. pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedRect.Pitch );
  656. }
  657. #ifndef RECORD_TEXTURES
  658. RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
  659. RECORD_INT( info.m_TextureHandle );
  660. RECORD_INT( info.m_nCopy );
  661. RECORD_INT( info.m_nLevel );
  662. RECORD_INT( info.m_CubeFaceID );
  663. #endif
  664. {
  665. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UnlockRect", __FUNCTION__ );
  666. if ( FAILED( pTextureLevel->UnlockRect() ) )
  667. {
  668. Warning( "CShaderAPIDX8::BlitTextureBits: couldn't unlock texture rect\n" );
  669. pTextureLevel->Release();
  670. return;
  671. }
  672. }
  673. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - pTextureLevel->Release", __FUNCTION__ );
  674. pTextureLevel->Release();
  675. }
  676. #endif
  677. //-----------------------------------------------------------------------------
  678. // Puts 2D texture data into 360 gpu memory.
  679. //-----------------------------------------------------------------------------
  680. #if defined( _X360 )
  681. static void BlitSurfaceBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  682. {
  683. // xbox textures are NOT backed in gpu memory contiguously
  684. // stride details are critical - see [Xbox 360 Texture Storage]
  685. // a d3dformat identifier on the xbox is tiled, the same d3dformat on the pc is expected linear to the app
  686. // we purposely hide the tiling here, otherwise much confusion for the pc
  687. // the *entire* target must be un-tiled *only* before any *subrect* blitting linear work
  688. // the *entire* target must then be re-tiled after the *subrect* blit
  689. // procedural textures require this to subrect blit their new portions correctly
  690. // the tiling dance can be avoided if the source and target match in tiled state during a full rect blit
  691. if ( info.m_bSrcIsTiled )
  692. {
  693. // not supporting subrect blitting from a tiled source
  694. Assert( 0 );
  695. return;
  696. }
  697. CUtlBuffer formatConvertMemory;
  698. unsigned char *pSrcData = info.m_pSrcData;
  699. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  700. if ( dstFormat != info.m_SrcFormat )
  701. {
  702. if ( !info.m_bCanConvertFormat )
  703. {
  704. // texture is expected to be in target format
  705. // not supporting conversion of a tiled source
  706. Assert( 0 );
  707. return;
  708. }
  709. int srcSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, info.m_SrcFormat, false );
  710. int dstSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, dstFormat, false );
  711. formatConvertMemory.EnsureCapacity( dstSize );
  712. // due to format conversion, source is in non-native order
  713. ImageLoader::PreConvertSwapImageData( (unsigned char*)info.m_pSrcData, srcSize, info.m_SrcFormat, info.m_nWidth, srcStride );
  714. // slow conversion operation
  715. if ( !ShaderUtil()->ConvertImageFormat(
  716. info.m_pSrcData,
  717. info.m_SrcFormat,
  718. (unsigned char*)formatConvertMemory.Base(),
  719. dstFormat,
  720. info.m_nWidth,
  721. info.m_nHeight,
  722. srcStride,
  723. 0 ) )
  724. {
  725. // conversion failed
  726. Assert( 0 );
  727. return;
  728. }
  729. // due to format conversion, source must have been in non-native order
  730. ImageLoader::PostConvertSwapImageData( (unsigned char*)formatConvertMemory.Base(), dstSize, dstFormat );
  731. pSrcData = (unsigned char*)formatConvertMemory.Base();
  732. }
  733. // get the top mip level info (needed for proper sub mip access)
  734. XGTEXTURE_DESC baseDesc;
  735. XGGetTextureDesc( info.m_pTexture, 0, &baseDesc );
  736. bool bDstIsTiled = XGIsTiledFormat( baseDesc.Format ) == TRUE;
  737. // get the target mip level info
  738. XGTEXTURE_DESC mipDesc;
  739. XGGetTextureDesc( info.m_pTexture, info.m_nLevel, &mipDesc );
  740. bool bFullSurfBlit = ( mipDesc.Width == (unsigned)info.m_nWidth && mipDesc.Height == (unsigned)info.m_nHeight );
  741. // get the mip level of the texture we want to write into
  742. IDirect3DSurface* pTextureLevel;
  743. HRESULT hr = GetSurfaceFromTexture( info.m_pTexture, info.m_nLevel, info.m_CubeFaceID, &pTextureLevel );
  744. if ( FAILED( hr ) )
  745. {
  746. Warning( "CShaderAPIDX8::BlitTextureBits: GetSurfaceFromTexture() failure\n" );
  747. return;
  748. }
  749. CUtlBuffer scratchMemory;
  750. D3DLOCKED_RECT lockedRect;
  751. hr = pTextureLevel->LockRect( &lockedRect, NULL, D3DLOCK_NOSYSLOCK );
  752. if ( FAILED( hr ) )
  753. {
  754. Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect\n" );
  755. goto cleanUp;
  756. }
  757. unsigned char *pTargetImage = (unsigned char *)lockedRect.pBits;
  758. POINT p;
  759. p.x = xOffset;
  760. p.y = yOffset;
  761. RECT r;
  762. r.left = 0;
  763. r.top = 0;
  764. r.right = info.m_nWidth;
  765. r.bottom = info.m_nHeight;
  766. int blockSize = mipDesc.Width/mipDesc.WidthInBlocks;
  767. if ( !srcStride )
  768. {
  769. srcStride = (mipDesc.Width/blockSize)*mipDesc.BytesPerBlock;
  770. }
  771. // subrect blitting path
  772. if ( !bDstIsTiled )
  773. {
  774. // Copy the subrect without conversion
  775. hr = XGCopySurface(
  776. pTargetImage,
  777. mipDesc.RowPitch,
  778. mipDesc.Width,
  779. mipDesc.Height,
  780. mipDesc.Format,
  781. &p,
  782. pSrcData,
  783. srcStride,
  784. mipDesc.Format,
  785. &r,
  786. 0,
  787. 0 );
  788. if ( FAILED( hr ) )
  789. {
  790. Warning( "CShaderAPIDX8::BlitTextureBits: failed subrect copy\n" );
  791. goto cleanUp;
  792. }
  793. }
  794. else
  795. {
  796. int tileFlags = 0;
  797. if ( !( mipDesc.Flags & XGTDESC_PACKED ) )
  798. tileFlags |= XGTILE_NONPACKED;
  799. if ( mipDesc.Flags & XGTDESC_BORDERED )
  800. tileFlags |= XGTILE_BORDER;
  801. // tile the temp store back into the target surface
  802. XGTileTextureLevel(
  803. baseDesc.Width,
  804. baseDesc.Height,
  805. info.m_nLevel,
  806. XGGetGpuFormat( baseDesc.Format ),
  807. tileFlags,
  808. pTargetImage,
  809. &p,
  810. pSrcData,
  811. srcStride,
  812. &r );
  813. }
  814. hr = pTextureLevel->UnlockRect();
  815. if ( FAILED( hr ) )
  816. {
  817. Warning( "CShaderAPIDX8::BlitTextureBits: couldn't unlock texture rect\n" );
  818. goto cleanUp;
  819. }
  820. cleanUp:
  821. pTextureLevel->Release();
  822. }
  823. #endif
  824. //-----------------------------------------------------------------------------
  825. // Blit in bits
  826. //-----------------------------------------------------------------------------
  827. #if !defined( _X360 )
  828. static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  829. {
  830. D3DBOX srcBox;
  831. D3DLOCKED_BOX lockedBox;
  832. srcBox.Left = xOffset;
  833. srcBox.Right = xOffset + info.m_nWidth;
  834. srcBox.Top = yOffset;
  835. srcBox.Bottom = yOffset + info.m_nHeight;
  836. srcBox.Front = info.m_nZOffset;
  837. srcBox.Back = info.m_nZOffset + 1;
  838. #ifndef RECORD_TEXTURES
  839. RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
  840. RECORD_INT( info.m_TextureHandle );
  841. RECORD_INT( info.m_nCopy );
  842. RECORD_INT( info.m_nLevel );
  843. RECORD_INT( info.m_CubeFaceID );
  844. RECORD_STRUCT( &srcRect, sizeof(srcRect) );
  845. RECORD_INT( D3DLOCK_NOSYSLOCK );
  846. #endif
  847. IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
  848. if ( FAILED( pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, &srcBox, D3DLOCK_NOSYSLOCK ) ) )
  849. {
  850. Warning( "BlitVolumeBits: couldn't lock volume texture rect\n" );
  851. return;
  852. }
  853. // garymcthack : need to make a recording command for this.
  854. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  855. unsigned char *pImage = (unsigned char *)lockedBox.pBits;
  856. ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
  857. pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedBox.RowPitch );
  858. #ifndef RECORD_TEXTURES
  859. RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
  860. RECORD_INT( info.m_TextureHandle );
  861. RECORD_INT( info.m_nCopy );
  862. RECORD_INT( info.m_nLevel );
  863. RECORD_INT( info.m_CubeFaceID );
  864. #endif
  865. if ( FAILED( pVolumeTexture->UnlockBox( info.m_nLevel ) ) )
  866. {
  867. Warning( "BlitVolumeBits: couldn't unlock volume texture rect\n" );
  868. return;
  869. }
  870. }
  871. #endif
  872. //-----------------------------------------------------------------------------
  873. // Puts 3D texture data into 360 gpu memory.
  874. // Does not support any subvolume or slice blitting.
  875. //-----------------------------------------------------------------------------
  876. #if defined( _X360 )
  877. static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  878. {
  879. if ( xOffset || yOffset || info.m_nZOffset || srcStride )
  880. {
  881. // not supporting any subvolume blitting
  882. // the entire volume per mip must be blitted
  883. Assert( 0 );
  884. return;
  885. }
  886. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  887. if ( dstFormat != info.m_SrcFormat )
  888. {
  889. // texture is expected to be in target format
  890. // not supporting conversion
  891. Assert( 0 );
  892. return;
  893. }
  894. // get the top mip level info (needed for proper sub mip access)
  895. XGTEXTURE_DESC baseDesc;
  896. XGGetTextureDesc( info.m_pTexture, 0, &baseDesc );
  897. bool bDstIsTiled = XGIsTiledFormat( baseDesc.Format ) == TRUE;
  898. if ( info.m_bSrcIsTiled && !bDstIsTiled )
  899. {
  900. // not supporting a tiled source into an untiled target
  901. Assert( 0 );
  902. return;
  903. }
  904. // get the mip level info
  905. XGTEXTURE_DESC mipDesc;
  906. XGGetTextureDesc( info.m_pTexture, info.m_nLevel, &mipDesc );
  907. bool bFullSurfBlit = ( mipDesc.Width == (unsigned int)info.m_nWidth && mipDesc.Height == (unsigned int)info.m_nHeight );
  908. if ( !bFullSurfBlit )
  909. {
  910. // not supporting subrect blitting
  911. Assert( 0 );
  912. return;
  913. }
  914. D3DLOCKED_BOX lockedBox;
  915. // get the mip level of the volume we want to write into
  916. IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
  917. HRESULT hr = pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, NULL, D3DLOCK_NOSYSLOCK );
  918. if ( FAILED( hr ) )
  919. {
  920. Warning( "CShaderAPIDX8::BlitVolumeBits: Couldn't lock volume box\n" );
  921. return;
  922. }
  923. unsigned char *pSrcData = info.m_pSrcData;
  924. unsigned char *pTargetImage = (unsigned char *)lockedBox.pBits;
  925. int tileFlags = 0;
  926. if ( !( mipDesc.Flags & XGTDESC_PACKED ) )
  927. tileFlags |= XGTILE_NONPACKED;
  928. if ( mipDesc.Flags & XGTDESC_BORDERED )
  929. tileFlags |= XGTILE_BORDER;
  930. if ( !info.m_bSrcIsTiled && bDstIsTiled )
  931. {
  932. // tile the source directly into the target surface
  933. XGTileVolumeTextureLevel(
  934. baseDesc.Width,
  935. baseDesc.Height,
  936. baseDesc.Depth,
  937. info.m_nLevel,
  938. XGGetGpuFormat( baseDesc.Format ),
  939. tileFlags,
  940. pTargetImage,
  941. NULL,
  942. pSrcData,
  943. mipDesc.RowPitch,
  944. mipDesc.SlicePitch,
  945. NULL );
  946. }
  947. else if ( !info.m_bSrcIsTiled && !bDstIsTiled )
  948. {
  949. // not implemented yet
  950. Assert( 0 );
  951. }
  952. else
  953. {
  954. // not implemented yet
  955. Assert( 0 );
  956. }
  957. hr = pVolumeTexture->UnlockBox( info.m_nLevel );
  958. if ( FAILED( hr ) )
  959. {
  960. Warning( "CShaderAPIDX8::BlitVolumeBits: couldn't unlock volume box\n" );
  961. return;
  962. }
  963. }
  964. #endif
  965. // FIXME: How do I blit from D3DPOOL_SYSTEMMEM to D3DPOOL_MANAGED? I used to use CopyRects for this. UpdateSurface doesn't work because it can't blit to anything besides D3DPOOL_DEFAULT.
  966. // We use this only in the case where we need to create a < 4x4 miplevel for a compressed texture. We end up creating a 4x4 system memory texture, and blitting it into the proper miplevel.
  967. // 6) LockRects should be used for copying between SYSTEMMEM and
  968. // MANAGED. For such a small copy, you'd avoid a significant
  969. // amount of overhead from the old CopyRects code. Ideally, you
  970. // should just lock the bottom of MANAGED and generate your
  971. // sub-4x4 data there.
  972. // NOTE: IF YOU CHANGE THIS, CHANGE THE VERSION IN PLAYBACK.CPP!!!!
  973. static void BlitTextureBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  974. {
  975. #ifdef RECORD_TEXTURES
  976. RECORD_COMMAND( DX8_BLIT_TEXTURE_BITS, 14 );
  977. RECORD_INT( info.m_TextureHandle );
  978. RECORD_INT( info.m_nCopy );
  979. RECORD_INT( info.m_nLevel );
  980. RECORD_INT( info.m_CubeFaceID );
  981. RECORD_INT( xOffset );
  982. RECORD_INT( yOffset );
  983. RECORD_INT( info.m_nZOffset );
  984. RECORD_INT( info.m_nWidth );
  985. RECORD_INT( info.m_nHeight );
  986. RECORD_INT( info.m_SrcFormat );
  987. RECORD_INT( srcStride );
  988. RECORD_INT( GetImageFormat( info.m_pTexture ) );
  989. // strides are in bytes.
  990. int srcDataSize;
  991. if ( srcStride == 0 )
  992. {
  993. srcDataSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, info.m_SrcFormat, false );
  994. }
  995. else
  996. {
  997. srcDataSize = srcStride * info.m_nHeight;
  998. }
  999. RECORD_INT( srcDataSize );
  1000. RECORD_STRUCT( info.m_pSrcData, srcDataSize );
  1001. #endif // RECORD_TEXTURES
  1002. if ( !IsVolumeTexture( info.m_pTexture ) )
  1003. {
  1004. Assert( info.m_nZOffset == 0 );
  1005. BlitSurfaceBits( info, xOffset, yOffset, srcStride );
  1006. }
  1007. else
  1008. {
  1009. BlitVolumeBits( info, xOffset, yOffset, srcStride );
  1010. }
  1011. }
  1012. //-----------------------------------------------------------------------------
  1013. // Texture image upload
  1014. //-----------------------------------------------------------------------------
  1015. void LoadTexture( TextureLoadInfo_t &info )
  1016. {
  1017. MEM_ALLOC_D3D_CREDIT();
  1018. Assert( info.m_pSrcData );
  1019. Assert( info.m_pTexture );
  1020. #ifdef _DEBUG
  1021. ImageFormat format = GetImageFormat( info.m_pTexture );
  1022. Assert( (format != -1) && (format == FindNearestSupportedFormat( format, false, false, false )) );
  1023. #endif
  1024. // Copy in the bits...
  1025. BlitTextureBits( info, 0, 0, 0 );
  1026. }
  1027. void LoadVolumeTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
  1028. {
  1029. if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_VOLUMETEXTURE )
  1030. {
  1031. Assert( 0 );
  1032. return;
  1033. }
  1034. IDirect3DVolumeTexture9 *pVolTex = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
  1035. D3DVOLUME_DESC desc;
  1036. if ( pVolTex->GetLevelDesc( 0, &desc ) != S_OK )
  1037. {
  1038. Warning( "LoadVolumeTextureFromVTF: couldn't get texture level description\n" );
  1039. return;
  1040. }
  1041. int iMipCount = pVolTex->GetLevelCount();
  1042. if ( pVTF->Depth() != (int)desc.Depth || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->MipCount() < iMipCount )
  1043. {
  1044. Warning( "LoadVolumeTextureFromVTF: VTF dimensions do not match texture\n" );
  1045. return;
  1046. }
  1047. TextureLoadInfo_t sliceInfo = info;
  1048. #if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  1049. IDirect3DVolumeTexture9 *pStagingTexture = NULL;
  1050. if ( !info.m_bTextureIsLockable )
  1051. {
  1052. IDirect3DVolumeTexture9 *pTemp;
  1053. if ( Dx9Device()->CreateVolumeTexture( desc.Width, desc.Height, desc.Depth, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
  1054. {
  1055. Warning( "LoadVolumeTextureFromVTF: failed to create temporary staging texture\n" );
  1056. return;
  1057. }
  1058. sliceInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
  1059. sliceInfo.m_bTextureIsLockable = true;
  1060. pStagingTexture = pTemp;
  1061. }
  1062. #endif
  1063. for ( int iMip = 0; iMip < iMipCount; ++iMip )
  1064. {
  1065. int w, h, d;
  1066. pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
  1067. sliceInfo.m_nLevel = iMip;
  1068. sliceInfo.m_nWidth = w;
  1069. sliceInfo.m_nHeight = h;
  1070. for ( int iSlice = 0; iSlice < d; ++iSlice )
  1071. {
  1072. sliceInfo.m_nZOffset = iSlice;
  1073. sliceInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, 0, iMip, 0, 0, iSlice );
  1074. BlitTextureBits( sliceInfo, 0, 0, 0 );
  1075. }
  1076. }
  1077. #if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  1078. if ( pStagingTexture )
  1079. {
  1080. if ( Dx9Device()->UpdateTexture( pStagingTexture, pVolTex ) != S_OK )
  1081. {
  1082. Warning( "LoadVolumeTextureFromVTF: volume UpdateTexture failed\n" );
  1083. }
  1084. pStagingTexture->Release();
  1085. }
  1086. #endif
  1087. }
  1088. void LoadCubeTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
  1089. {
  1090. if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_CUBETEXTURE )
  1091. {
  1092. Assert( 0 );
  1093. return;
  1094. }
  1095. IDirect3DCubeTexture9 *pCubeTex = static_cast<IDirect3DCubeTexture9*>( info.m_pTexture );
  1096. D3DSURFACE_DESC desc;
  1097. if ( pCubeTex->GetLevelDesc( 0, &desc ) != S_OK )
  1098. {
  1099. Warning( "LoadCubeTextureFromVTF: couldn't get texture level description\n" );
  1100. return;
  1101. }
  1102. int iMipCount = pCubeTex->GetLevelCount();
  1103. if ( pVTF->Depth() != 1 || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->FaceCount() < 6 || pVTF->MipCount() < iMipCount )
  1104. {
  1105. Warning( "LoadCubeTextureFromVTF: VTF dimensions do not match texture\n" );
  1106. return;
  1107. }
  1108. TextureLoadInfo_t faceInfo = info;
  1109. #if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  1110. IDirect3DCubeTexture9 *pStagingTexture = NULL;
  1111. if ( !info.m_bTextureIsLockable )
  1112. {
  1113. IDirect3DCubeTexture9 *pTemp;
  1114. if ( Dx9Device()->CreateCubeTexture( desc.Width, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
  1115. {
  1116. Warning( "LoadCubeTextureFromVTF: failed to create temporary staging texture\n" );
  1117. return;
  1118. }
  1119. faceInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
  1120. faceInfo.m_bTextureIsLockable = true;
  1121. pStagingTexture = pTemp;
  1122. }
  1123. #endif
  1124. for ( int iMip = 0; iMip < iMipCount; ++iMip )
  1125. {
  1126. int w, h, d;
  1127. pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
  1128. faceInfo.m_nLevel = iMip;
  1129. faceInfo.m_nWidth = w;
  1130. faceInfo.m_nHeight = h;
  1131. for ( int iFace = 0; iFace < 6; ++iFace )
  1132. {
  1133. faceInfo.m_CubeFaceID = (D3DCUBEMAP_FACES) iFace;
  1134. faceInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, iFace, iMip );
  1135. BlitTextureBits( faceInfo, 0, 0, 0 );
  1136. }
  1137. }
  1138. #if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  1139. if ( pStagingTexture )
  1140. {
  1141. if ( Dx9Device()->UpdateTexture( pStagingTexture, pCubeTex ) != S_OK )
  1142. {
  1143. Warning( "LoadCubeTextureFromVTF: cube UpdateTexture failed\n" );
  1144. }
  1145. pStagingTexture->Release();
  1146. }
  1147. #endif
  1148. }
  1149. void LoadTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
  1150. {
  1151. TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 );
  1152. if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_TEXTURE )
  1153. {
  1154. Assert( 0 );
  1155. return;
  1156. }
  1157. IDirect3DTexture9 *pTex = static_cast<IDirect3DTexture9*>( info.m_pTexture );
  1158. D3DSURFACE_DESC desc;
  1159. {
  1160. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - GetLevelDesc", __FUNCTION__ );
  1161. if ( pTex->GetLevelDesc( 0, &desc ) != S_OK )
  1162. {
  1163. Warning( "LoadTextureFromVTF: couldn't get texture level description\n" );
  1164. return;
  1165. }
  1166. }
  1167. int iMipCount = pTex->GetLevelCount();
  1168. if ( pVTF->Depth() != 1 || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->MipCount() < iMipCount || pVTF->FaceCount() <= (int)info.m_CubeFaceID )
  1169. {
  1170. Warning( "LoadTextureFromVTF: VTF dimensions do not match texture\n" );
  1171. return;
  1172. }
  1173. // Info may have a cube face ID if we are falling back to 2D sphere map support
  1174. TextureLoadInfo_t mipInfo = info;
  1175. int iVTFFaceNum = info.m_CubeFaceID;
  1176. mipInfo.m_CubeFaceID = (D3DCUBEMAP_FACES)0;
  1177. #if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  1178. // If blitting more than one mip level of an unlockable texture, create a temporary
  1179. // texture for all mip levels only call UpdateTexture once. For textures with
  1180. // only a single mip level, fall back on the support in BlitSurfaceBits. -henryg
  1181. IDirect3DTexture9 *pStagingTexture = NULL;
  1182. if ( !info.m_bTextureIsLockable && iMipCount > 1 )
  1183. {
  1184. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - CreateSysmemTexture", __FUNCTION__ );
  1185. IDirect3DTexture9 *pTemp;
  1186. if ( Dx9Device()->CreateTexture( desc.Width, desc.Height, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
  1187. {
  1188. Warning( "LoadTextureFromVTF: failed to create temporary staging texture\n" );
  1189. return;
  1190. }
  1191. mipInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
  1192. mipInfo.m_bTextureIsLockable = true;
  1193. pStagingTexture = pTemp;
  1194. }
  1195. #endif
  1196. // Get the clamped resolutions from the VTF, then apply any clamping we've done from the higher level code.
  1197. // (For example, we chop off the bottom of the mipmap pyramid at 32x32--that is reflected in iMipCount, so
  1198. // honor that here).
  1199. int finest = 0, coarsest = 0;
  1200. pVTF->GetMipmapRange( &finest, &coarsest );
  1201. finest = Min( finest, iMipCount - 1 );
  1202. coarsest = Min( coarsest, iMipCount - 1 );
  1203. Assert( finest <= coarsest && coarsest < iMipCount );
  1204. {
  1205. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - BlitTextureBits", __FUNCTION__ );
  1206. for ( int iMip = finest; iMip <= coarsest; ++iMip )
  1207. {
  1208. int w, h, d;
  1209. pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
  1210. mipInfo.m_nLevel = iMip;
  1211. mipInfo.m_nWidth = w;
  1212. mipInfo.m_nHeight = h;
  1213. mipInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, iVTFFaceNum, iMip );
  1214. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - BlitTextureBits - %d", __FUNCTION__, iMip );
  1215. BlitTextureBits( mipInfo, 0, 0, 0 );
  1216. }
  1217. }
  1218. #if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  1219. if ( pStagingTexture )
  1220. {
  1221. if ( ( coarsest - finest + 1 ) == iMipCount )
  1222. {
  1223. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateTexture", __FUNCTION__ );
  1224. if ( Dx9Device()->UpdateTexture( pStagingTexture, pTex ) != S_OK )
  1225. {
  1226. Warning( "LoadTextureFromVTF: UpdateTexture failed\n" );
  1227. }
  1228. }
  1229. else
  1230. {
  1231. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface", __FUNCTION__ );
  1232. for ( int mip = finest; mip <= coarsest; ++mip )
  1233. {
  1234. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface - %d", __FUNCTION__, mip );
  1235. IDirect3DSurface9 *pSrcSurf = NULL,
  1236. *pDstSurf = NULL;
  1237. if ( pStagingTexture->GetSurfaceLevel( mip, &pSrcSurf ) != S_OK )
  1238. Warning( "LoadTextureFromVTF: couldn't get surface level %d for system surface\n", mip );
  1239. if ( pTex->GetSurfaceLevel( mip, &pDstSurf ) != S_OK )
  1240. Warning( "LoadTextureFromVTF: couldn't get surface level %d for dest surface\n", mip );
  1241. {
  1242. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface - Call ", __FUNCTION__, mip );
  1243. if ( !pSrcSurf || !pDstSurf || Dx9Device()->UpdateSurface( pSrcSurf, NULL, pDstSurf, NULL ) != S_OK )
  1244. Warning( "LoadTextureFromVTF: surface update failed.\n" );
  1245. }
  1246. if ( pSrcSurf )
  1247. pSrcSurf->Release();
  1248. if ( pDstSurf )
  1249. pDstSurf->Release();
  1250. }
  1251. }
  1252. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - Cleanup", __FUNCTION__ );
  1253. pStagingTexture->Release();
  1254. }
  1255. #endif
  1256. }
  1257. //-----------------------------------------------------------------------------
  1258. // Upload to a sub-piece of a texture
  1259. //-----------------------------------------------------------------------------
  1260. void LoadSubTexture( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  1261. {
  1262. Assert( info.m_pSrcData );
  1263. Assert( info.m_pTexture );
  1264. #if defined( _X360 )
  1265. // xboxissue - not supporting subrect swizzling
  1266. Assert( !info.m_bSrcIsTiled );
  1267. #endif
  1268. #ifdef _DEBUG
  1269. ImageFormat format = GetImageFormat( info.m_pTexture );
  1270. Assert( (format == FindNearestSupportedFormat(format, false, false, false )) && (format != -1) );
  1271. #endif
  1272. // Copy in the bits...
  1273. BlitTextureBits( info, xOffset, yOffset, srcStride );
  1274. }
  1275. //-----------------------------------------------------------------------------
  1276. // Returns the size of texture memory, in MB
  1277. //-----------------------------------------------------------------------------
  1278. // Helps with startup time.. we don't use the texture memory size for anything anyways
  1279. #define DONT_CHECK_MEM
  1280. int ComputeTextureMemorySize( const GUID &nDeviceGUID, D3DDEVTYPE deviceType )
  1281. {
  1282. #if defined( _X360 )
  1283. return 0;
  1284. #elif defined( DONT_CHECK_MEM )
  1285. return (deviceType == D3DDEVTYPE_REF) ? (64 * 1024 * 1024) : 102236160;
  1286. #else
  1287. FileHandle_t file = g_pFullFileSystem->Open( "vidcfg.bin", "rb", "EXECUTABLE_PATH" );
  1288. if ( file )
  1289. {
  1290. GUID deviceId;
  1291. int texSize;
  1292. g_pFullFileSystem->Read( &deviceId, sizeof(deviceId), file );
  1293. g_pFullFileSystem->Read( &texSize, sizeof(texSize), file );
  1294. g_pFullFileSystem->Close( file );
  1295. if ( nDeviceGUID == deviceId )
  1296. {
  1297. return texSize;
  1298. }
  1299. }
  1300. // How much texture memory?
  1301. if (deviceType == D3DDEVTYPE_REF)
  1302. return 64 * 1024 * 1024;
  1303. // Sadly, the only way to compute texture memory size
  1304. // is to allocate a crapload of textures until we can't any more
  1305. ImageFormat fmt = FindNearestSupportedFormat( IMAGE_FORMAT_BGR565, false, false, false );
  1306. int textureSize = ShaderUtil()->GetMemRequired( 256, 256, 1, fmt, false );
  1307. int totalSize = 0;
  1308. CUtlVector< IDirect3DBaseTexture* > textures;
  1309. s_bTestingVideoMemorySize = true;
  1310. while (true)
  1311. {
  1312. RECORD_COMMAND( DX8_CREATE_TEXTURE, 7 );
  1313. RECORD_INT( textures.Count() );
  1314. RECORD_INT( 256 );
  1315. RECORD_INT( 256 );
  1316. RECORD_INT( ImageLoader::ImageFormatToD3DFormat(fmt) );
  1317. RECORD_INT( 1 );
  1318. RECORD_INT( false );
  1319. RECORD_INT( 1 );
  1320. IDirect3DBaseTexture* pTex = CreateD3DTexture( 256, 256, 1, fmt, 1, 0 );
  1321. if (!pTex)
  1322. break;
  1323. totalSize += textureSize;
  1324. textures.AddToTail( pTex );
  1325. }
  1326. s_bTestingVideoMemorySize = false;
  1327. // Free all the temp textures
  1328. for (int i = textures.Size(); --i >= 0; )
  1329. {
  1330. RECORD_COMMAND( DX8_DESTROY_TEXTURE, 1 );
  1331. RECORD_INT( i );
  1332. DestroyD3DTexture( textures[i] );
  1333. }
  1334. file = g_pFullFileSystem->Open( "vidcfg.bin", "wb", "EXECUTABLE_PATH" );
  1335. if ( file )
  1336. {
  1337. g_pFullFileSystem->Write( &nDeviceGUID, sizeof(GUID), file );
  1338. g_pFullFileSystem->Write( &totalSize, sizeof(totalSize), file );
  1339. g_pFullFileSystem->Close( file );
  1340. }
  1341. return totalSize;
  1342. #endif
  1343. }