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.

1217 lines
34 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "locald3dtypes.h"
  9. #include "texturedx8.h"
  10. #include "shaderapidx8_global.h"
  11. #include "colorformatdx8.h"
  12. #include "shaderapi/ishaderutil.h"
  13. #include "materialsystem/imaterialsystem.h"
  14. #include "utlvector.h"
  15. #include "recording.h"
  16. #include "shaderapi/ishaderapi.h"
  17. #include "filesystem.h"
  18. #include "locald3dtypes.h"
  19. #include "textureheap.h"
  20. #include "tier1/utlbuffer.h"
  21. #include "tier1/callqueue.h"
  22. #include "tier0/vprof.h"
  23. #include "tier0/memdbgon.h"
  24. #ifdef _WIN32
  25. #pragma warning (disable:4189 4701)
  26. #endif
  27. static int s_TextureCount = 0;
  28. //-----------------------------------------------------------------------------
  29. // Stats...
  30. //-----------------------------------------------------------------------------
  31. int TextureCount()
  32. {
  33. return s_TextureCount;
  34. }
  35. static bool IsVolumeTexture( IDirect3DBaseTexture* pBaseTexture )
  36. {
  37. if ( !pBaseTexture )
  38. {
  39. return false;
  40. }
  41. return ( pBaseTexture->GetType() == D3DRTYPE_VOLUMETEXTURE );
  42. }
  43. static HRESULT GetLevelDesc( IDirect3DBaseTexture* pBaseTexture, UINT level, D3DSURFACE_DESC* pDesc )
  44. {
  45. MEM_ALLOC_D3D_CREDIT();
  46. if ( !pBaseTexture )
  47. {
  48. return ( HRESULT )-1;
  49. }
  50. HRESULT hr;
  51. switch( pBaseTexture->GetType() )
  52. {
  53. case D3DRTYPE_TEXTURE:
  54. hr = ( ( IDirect3DTexture * )pBaseTexture )->GetLevelDesc( level, pDesc );
  55. break;
  56. case D3DRTYPE_CUBETEXTURE:
  57. hr = ( ( IDirect3DCubeTexture * )pBaseTexture )->GetLevelDesc( level, pDesc );
  58. break;
  59. default:
  60. return ( HRESULT )-1;
  61. }
  62. return hr;
  63. }
  64. static HRESULT GetSurfaceFromTexture( IDirect3DBaseTexture* pBaseTexture, UINT level,
  65. D3DCUBEMAP_FACES cubeFaceID, IDirect3DSurface** ppSurfLevel )
  66. {
  67. MEM_ALLOC_D3D_CREDIT();
  68. if ( !pBaseTexture )
  69. {
  70. return ( HRESULT )-1;
  71. }
  72. HRESULT hr;
  73. switch( pBaseTexture->GetType() )
  74. {
  75. case D3DRTYPE_TEXTURE:
  76. hr = ( ( IDirect3DTexture * )pBaseTexture )->GetSurfaceLevel( level, ppSurfLevel );
  77. break;
  78. case D3DRTYPE_CUBETEXTURE:
  79. if (cubeFaceID !=0)
  80. {
  81. //Debugger();
  82. }
  83. hr = ( ( IDirect3DCubeTexture * )pBaseTexture )->GetCubeMapSurface( cubeFaceID, level, ppSurfLevel );
  84. break;
  85. default:
  86. Assert(0);
  87. return ( HRESULT )-1;
  88. }
  89. return hr;
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Gets the image format of a texture
  93. //-----------------------------------------------------------------------------
  94. static ImageFormat GetImageFormat( IDirect3DBaseTexture* pTexture )
  95. {
  96. MEM_ALLOC_D3D_CREDIT();
  97. if ( pTexture )
  98. {
  99. HRESULT hr;
  100. if ( !IsVolumeTexture( pTexture ) )
  101. {
  102. D3DSURFACE_DESC desc;
  103. hr = GetLevelDesc( pTexture, 0, &desc );
  104. if ( !FAILED( hr ) )
  105. return ImageLoader::D3DFormatToImageFormat( desc.Format );
  106. }
  107. else
  108. {
  109. D3DVOLUME_DESC desc;
  110. IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( pTexture );
  111. hr = pVolumeTexture->GetLevelDesc( 0, &desc );
  112. if ( !FAILED( hr ) )
  113. return ImageLoader::D3DFormatToImageFormat( desc.Format );
  114. }
  115. }
  116. // Bogus baby!
  117. return (ImageFormat)-1;
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Allocates the D3DTexture
  121. //-----------------------------------------------------------------------------
  122. IDirect3DBaseTexture* CreateD3DTexture( int width, int height, int nDepth,
  123. ImageFormat dstFormat, int numLevels, int nCreationFlags, char *debugLabel ) // OK to skip the last param
  124. {
  125. if ( nDepth <= 0 )
  126. {
  127. nDepth = 1;
  128. }
  129. bool bIsCubeMap = ( nCreationFlags & TEXTURE_CREATE_CUBEMAP ) != 0;
  130. bool bIsRenderTarget = ( nCreationFlags & TEXTURE_CREATE_RENDERTARGET ) != 0;
  131. bool bManaged = ( nCreationFlags & TEXTURE_CREATE_MANAGED ) != 0;
  132. bool bIsDepthBuffer = ( nCreationFlags & TEXTURE_CREATE_DEPTHBUFFER ) != 0;
  133. bool bIsDynamic = ( nCreationFlags & TEXTURE_CREATE_DYNAMIC ) != 0;
  134. bool bAutoMipMap = ( nCreationFlags & TEXTURE_CREATE_AUTOMIPMAP ) != 0;
  135. bool bVertexTexture = ( nCreationFlags & TEXTURE_CREATE_VERTEXTEXTURE ) != 0;
  136. bool bAllowNonFilterable = ( nCreationFlags & TEXTURE_CREATE_UNFILTERABLE_OK ) != 0;
  137. bool bVolumeTexture = ( nDepth > 1 );
  138. bool bNoD3DBits = ( nCreationFlags & TEXTURE_CREATE_NOD3DMEMORY ) != 0;
  139. bool bSysMem = ( nCreationFlags & TEXTURE_CREATE_SYSMEM ) != 0;
  140. bool bDefaultPool = ( nCreationFlags & TEXTURE_CREATE_DEFAULT_POOL ) != 0;
  141. bool bCacheable = ( nCreationFlags & TEXTURE_CREATE_CACHEABLE ) != 0;
  142. bool bSRGB = (nCreationFlags & TEXTURE_CREATE_SRGB) != 0; // for Posix/GL only
  143. bool bAnsiotropic = (nCreationFlags & TEXTURE_CREATE_ANISOTROPIC) != 0; // for Posix/GL only
  144. // NOTE: This function shouldn't be used for creating depth buffers!
  145. Assert( !bIsDepthBuffer );
  146. D3DFORMAT d3dFormat = D3DFMT_UNKNOWN;
  147. if ( IsX360() )
  148. {
  149. // 360 does not support vertex textures
  150. // 360 render target creation path is for the target as a texture source (NOT the EDRAM version)
  151. // use normal texture format rules
  152. Assert( !bVertexTexture );
  153. if ( !bVertexTexture )
  154. {
  155. d3dFormat = FindNearestSupportedFormat( dstFormat, false, false, false );
  156. }
  157. }
  158. else
  159. {
  160. d3dFormat = FindNearestSupportedFormat( dstFormat, bVertexTexture, bIsRenderTarget, bAllowNonFilterable );
  161. }
  162. if ( d3dFormat == D3DFMT_UNKNOWN )
  163. {
  164. Warning( "ShaderAPIDX8::CreateD3DTexture: Invalid color format!\n" );
  165. Assert( 0 );
  166. return 0;
  167. }
  168. IDirect3DBaseTexture* pBaseTexture = NULL;
  169. IDirect3DTexture* pD3DTexture = NULL;
  170. IDirect3DCubeTexture* pD3DCubeTexture = NULL;
  171. IDirect3DVolumeTexture* pD3DVolumeTexture = NULL;
  172. HRESULT hr = S_OK;
  173. DWORD usage = 0;
  174. if ( bIsRenderTarget )
  175. {
  176. usage |= D3DUSAGE_RENDERTARGET;
  177. }
  178. if ( bIsDynamic )
  179. {
  180. usage |= D3DUSAGE_DYNAMIC;
  181. }
  182. if ( bAutoMipMap )
  183. {
  184. usage |= D3DUSAGE_AUTOGENMIPMAP;
  185. }
  186. #ifdef DX_TO_GL_ABSTRACTION
  187. if ( bSRGB )
  188. {
  189. // This flag does not exist in real DX9... just for GL to know that this is an SRGB tex
  190. usage |= D3DUSAGE_TEXTURE_SRGB;
  191. }
  192. #endif
  193. #if defined( _PS3 )
  194. if ( bNoD3DBits && !bVolumeTexture )
  195. {
  196. // This flag does not exist in real DX9... tells GCM to defer allocating storage for the bits (until CShaderAPIDx8::PostQueuedTexture)
  197. usage |= D3DUSAGE_TEXTURE_NOD3DMEMORY;
  198. }
  199. #endif
  200. if ( bIsCubeMap )
  201. {
  202. #if !defined( _X360 )
  203. hr = Dx9Device()->CreateCubeTexture(
  204. width,
  205. numLevels,
  206. usage,
  207. d3dFormat,
  208. bManaged ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT,
  209. &pD3DCubeTexture,
  210. NULL
  211. #if ( defined( DX_TO_GL_ABSTRACTION ) && !defined( _PS3 ) )
  212. , debugLabel // tex create funcs take extra arg for debug name on GL
  213. #endif
  214. );
  215. #else
  216. pD3DCubeTexture = g_TextureHeap.AllocCubeTexture( width, numLevels, usage, d3dFormat, bNoD3DBits );
  217. #endif
  218. pBaseTexture = pD3DCubeTexture;
  219. }
  220. else if ( bVolumeTexture )
  221. {
  222. Assert( !bNoD3DBits );
  223. #if !defined( _X360 )
  224. hr = Dx9Device()->CreateVolumeTexture(
  225. width,
  226. height,
  227. nDepth,
  228. numLevels,
  229. usage,
  230. d3dFormat,
  231. bManaged ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT,
  232. &pD3DVolumeTexture,
  233. NULL
  234. #if ( defined( DX_TO_GL_ABSTRACTION ) && !defined( _PS3 ) )
  235. , debugLabel // tex create funcs take extra arg for debug name on GL
  236. #endif
  237. );
  238. #else
  239. pD3DVolumeTexture = g_TextureHeap.AllocVolumeTexture( width, height, nDepth, numLevels, usage, d3dFormat );
  240. #endif
  241. pBaseTexture = pD3DVolumeTexture;
  242. }
  243. else
  244. {
  245. #if !defined( _X360 )
  246. // Override usage and managed params if using special hardware shadow depth map formats...
  247. if ( ( d3dFormat == NVFMT_RAWZ ) || ( d3dFormat == NVFMT_INTZ ) ||
  248. ( d3dFormat == D3DFMT_D16 ) || ( d3dFormat == D3DFMT_D24S8 ) ||
  249. ( d3dFormat == ATIFMT_D16 ) || ( d3dFormat == ATIFMT_D24S8 ) )
  250. {
  251. // Not putting D3DUSAGE_RENDERTARGET here causes D3D debug spew later, but putting the flag causes this create to fail...
  252. usage = D3DUSAGE_DEPTHSTENCIL;
  253. bManaged = false;
  254. }
  255. // Override managed param if using special null texture format
  256. if ( d3dFormat == NVFMT_NULL )
  257. {
  258. bManaged = false;
  259. }
  260. D3DPOOL d3dPool = D3DPOOL_DEFAULT;
  261. if ( bSysMem )
  262. d3dPool = D3DPOOL_SYSTEMMEM;
  263. else if ( bManaged )
  264. d3dPool = D3DPOOL_MANAGED;
  265. hr = Dx9Device()->CreateTexture(
  266. width,
  267. height,
  268. numLevels,
  269. usage,
  270. d3dFormat,
  271. d3dPool,
  272. &pD3DTexture,
  273. NULL
  274. #if ( defined( DX_TO_GL_ABSTRACTION ) && !defined( _PS3 ) )
  275. , debugLabel // tex create funcs take extra arg for debug name on GL
  276. #endif
  277. );
  278. #else
  279. pD3DTexture = g_TextureHeap.AllocTexture( width, height, numLevels, usage, d3dFormat, bNoD3DBits, bCacheable );
  280. if ( pD3DTexture == NULL )
  281. {
  282. Warning( "ShaderAPIDX8::CreateD3DTexture: TexureHeap out of memory.\n" );
  283. g_pMemAlloc->DumpStats();
  284. return 0;
  285. }
  286. #endif
  287. pBaseTexture = pD3DTexture;
  288. }
  289. if ( FAILED( hr ) )
  290. {
  291. switch ( hr )
  292. {
  293. case D3DERR_INVALIDCALL:
  294. Warning( "ShaderAPIDX8::CreateD3DTexture: D3DERR_INVALIDCALL\n" );
  295. break;
  296. case D3DERR_OUTOFVIDEOMEMORY:
  297. // This conditional is here so that we don't complain when testing
  298. // how much video memory we have. . this is kinda gross.
  299. if ( bManaged )
  300. {
  301. Warning( "ShaderAPIDX8::CreateD3DTexture: D3DERR_OUTOFVIDEOMEMORY\n" );
  302. }
  303. break;
  304. case E_OUTOFMEMORY:
  305. Warning( "ShaderAPIDX8::CreateD3DTexture: E_OUTOFMEMORY\n" );
  306. break;
  307. default:
  308. break;
  309. }
  310. return 0;
  311. }
  312. #ifdef MEASURE_DRIVER_ALLOCATIONS
  313. int nMipCount = numLevels;
  314. if ( !nMipCount )
  315. {
  316. while ( width > 1 || height > 1 )
  317. {
  318. width >>= 1;
  319. height >>= 1;
  320. ++nMipCount;
  321. }
  322. }
  323. int nMemUsed = nMipCount * 1.1f * 1024;
  324. if ( bIsCubeMap )
  325. {
  326. nMemUsed *= 6;
  327. }
  328. VPROF_INCREMENT_GROUP_COUNTER( "texture count", COUNTER_GROUP_NO_RESET, 1 );
  329. VPROF_INCREMENT_GROUP_COUNTER( "texture driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  330. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  331. #endif
  332. ++s_TextureCount;
  333. return pBaseTexture;
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Texture destruction
  337. //-----------------------------------------------------------------------------
  338. void ReleaseD3DTexture( IDirect3DBaseTexture* pD3DTex )
  339. {
  340. int ref = pD3DTex->Release();
  341. Assert( ref == 0 );
  342. }
  343. void DestroyD3DTexture( IDirect3DBaseTexture* pD3DTex )
  344. {
  345. if ( pD3DTex )
  346. {
  347. #ifdef MEASURE_DRIVER_ALLOCATIONS
  348. D3DRESOURCETYPE type = pD3DTex->GetType();
  349. int nMipCount = pD3DTex->GetLevelCount();
  350. if ( type == D3DRTYPE_CUBETEXTURE )
  351. {
  352. nMipCount *= 6;
  353. }
  354. int nMemUsed = nMipCount * 1.1f * 1024;
  355. VPROF_INCREMENT_GROUP_COUNTER( "texture count", COUNTER_GROUP_NO_RESET, -1 );
  356. VPROF_INCREMENT_GROUP_COUNTER( "texture driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  357. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  358. #endif
  359. #if !defined( _X360 )
  360. CMatRenderContextPtr pRenderContext( materials );
  361. ICallQueue *pCallQueue;
  362. if ( ( pCallQueue = pRenderContext->GetCallQueue() ) != NULL )
  363. {
  364. pCallQueue->QueueCall( ReleaseD3DTexture, pD3DTex );
  365. }
  366. else
  367. {
  368. ReleaseD3DTexture( pD3DTex );
  369. }
  370. #else
  371. g_TextureHeap.FreeTexture( pD3DTex );
  372. #endif
  373. --s_TextureCount;
  374. }
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose:
  378. // Input : *pTex -
  379. // Output : int
  380. //-----------------------------------------------------------------------------
  381. int GetD3DTextureRefCount( IDirect3DBaseTexture *pTex )
  382. {
  383. if ( !pTex )
  384. return 0;
  385. pTex->AddRef();
  386. int ref = pTex->Release();
  387. return ref;
  388. }
  389. //-----------------------------------------------------------------------------
  390. // See version 13 for a function that converts a texture to a mipmap (ConvertToMipmap)
  391. //-----------------------------------------------------------------------------
  392. //-----------------------------------------------------------------------------
  393. // Lock, unlock a texture...
  394. //-----------------------------------------------------------------------------
  395. static RECT s_LockedSrcRect;
  396. static D3DLOCKED_RECT s_LockedRect;
  397. #ifdef DBGFLAG_ASSERT
  398. static bool s_bInLock = false;
  399. #endif
  400. bool LockTexture( ShaderAPITextureHandle_t bindId, int copy, IDirect3DBaseTexture* pTexture, int level,
  401. D3DCUBEMAP_FACES cubeFaceID, int xOffset, int yOffset, int width, int height, bool bDiscard,
  402. CPixelWriter& writer )
  403. {
  404. Assert( !s_bInLock );
  405. IDirect3DSurface* pSurf;
  406. HRESULT hr = GetSurfaceFromTexture( pTexture, level, cubeFaceID, &pSurf );
  407. if ( FAILED( hr ) )
  408. return false;
  409. s_LockedSrcRect.left = xOffset;
  410. s_LockedSrcRect.right = xOffset + width;
  411. s_LockedSrcRect.top = yOffset;
  412. s_LockedSrcRect.bottom = yOffset + height;
  413. unsigned int flags = D3DLOCK_NOSYSLOCK;
  414. flags |= bDiscard ? D3DLOCK_DISCARD : 0;
  415. RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
  416. RECORD_INT( bindId );
  417. RECORD_INT( copy );
  418. RECORD_INT( level );
  419. RECORD_INT( cubeFaceID );
  420. RECORD_STRUCT( &s_LockedSrcRect, sizeof(s_LockedSrcRect) );
  421. RECORD_INT( flags );
  422. hr = pSurf->LockRect( &s_LockedRect, &s_LockedSrcRect, flags );
  423. pSurf->Release();
  424. if ( FAILED( hr ) )
  425. return false;
  426. writer.SetPixelMemory( GetImageFormat(pTexture), s_LockedRect.pBits, s_LockedRect.Pitch );
  427. #ifdef DBGFLAG_ASSERT
  428. s_bInLock = true;
  429. #endif
  430. return true;
  431. }
  432. void UnlockTexture( ShaderAPITextureHandle_t bindId, int copy, IDirect3DBaseTexture* pTexture, int level,
  433. D3DCUBEMAP_FACES cubeFaceID )
  434. {
  435. Assert( s_bInLock );
  436. IDirect3DSurface* pSurf;
  437. HRESULT hr = GetSurfaceFromTexture( pTexture, level, cubeFaceID, &pSurf );
  438. if (FAILED(hr))
  439. return;
  440. #ifdef RECORD_TEXTURES
  441. int width = s_LockedSrcRect.right - s_LockedSrcRect.left;
  442. int height = s_LockedSrcRect.bottom - s_LockedSrcRect.top;
  443. int imageFormatSize = ImageLoader::SizeInBytes( GetImageFormat( pTexture ) );
  444. Assert( imageFormatSize != 0 );
  445. int validDataBytesPerRow = imageFormatSize * width;
  446. int storeSize = validDataBytesPerRow * height;
  447. static CUtlVector< unsigned char > tmpMem;
  448. if( tmpMem.Size() < storeSize )
  449. {
  450. tmpMem.AddMultipleToTail( storeSize - tmpMem.Size() );
  451. }
  452. unsigned char *pDst = tmpMem.Base();
  453. unsigned char *pSrc = ( unsigned char * )s_LockedRect.pBits;
  454. RECORD_COMMAND( DX8_SET_TEXTURE_DATA, 3 );
  455. RECORD_INT( validDataBytesPerRow );
  456. RECORD_INT( height );
  457. int i;
  458. for( i = 0; i < height; i++ )
  459. {
  460. memcpy( pDst, pSrc, validDataBytesPerRow );
  461. pDst += validDataBytesPerRow;
  462. pSrc += s_LockedRect.Pitch;
  463. }
  464. RECORD_STRUCT( tmpMem.Base(), storeSize );
  465. #endif // RECORD_TEXTURES
  466. RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
  467. RECORD_INT( bindId );
  468. RECORD_INT( copy );
  469. RECORD_INT( level );
  470. RECORD_INT( cubeFaceID );
  471. hr = pSurf->UnlockRect();
  472. pSurf->Release();
  473. #ifdef DBGFLAG_ASSERT
  474. s_bInLock = false;
  475. #endif
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Compute texture size based on compression
  479. //-----------------------------------------------------------------------------
  480. static inline int DetermineGreaterPowerOfTwo( int val )
  481. {
  482. int num = 1;
  483. while (val > num)
  484. {
  485. num <<= 1;
  486. }
  487. return num;
  488. }
  489. inline int DeterminePowerOfTwo( int val )
  490. {
  491. int pow = 0;
  492. while ((val & 0x1) == 0x0)
  493. {
  494. val >>= 1;
  495. ++pow;
  496. }
  497. return pow;
  498. }
  499. //-----------------------------------------------------------------------------
  500. // Blit in bits
  501. //-----------------------------------------------------------------------------
  502. // NOTE: IF YOU CHANGE THIS, CHANGE THE VERSION IN PLAYBACK.CPP!!!!
  503. // OPTIMIZE??: could lock the texture directly instead of the surface in dx9.
  504. #if !defined( _X360 )
  505. static void BlitSurfaceBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  506. {
  507. // Get the level of the texture we want to write into
  508. IDirect3DSurface* pTextureLevel;
  509. if (info.m_CubeFaceID !=0)
  510. {
  511. //Debugger();
  512. }
  513. HRESULT hr = GetSurfaceFromTexture( info.m_pTexture, info.m_nLevel, info.m_CubeFaceID, &pTextureLevel );
  514. if ( FAILED( hr ) )
  515. return;
  516. RECT srcRect;
  517. D3DLOCKED_RECT lockedRect;
  518. srcRect.left = xOffset;
  519. srcRect.right = xOffset + info.m_nWidth;
  520. srcRect.top = yOffset;
  521. srcRect.bottom = yOffset + info.m_nHeight;
  522. #ifndef RECORD_TEXTURES
  523. RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
  524. RECORD_INT( info.m_TextureHandle );
  525. RECORD_INT( info.m_nCopy );
  526. RECORD_INT( info.m_nLevel );
  527. RECORD_INT( info.m_CubeFaceID );
  528. RECORD_STRUCT( &srcRect, sizeof(srcRect) );
  529. RECORD_INT( D3DLOCK_NOSYSLOCK );
  530. #endif
  531. // lock the region (could be the full surface or less)
  532. if ( FAILED( pTextureLevel->LockRect( &lockedRect, &srcRect, D3DLOCK_NOSYSLOCK ) ) )
  533. {
  534. Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect\n" );
  535. pTextureLevel->Release();
  536. return;
  537. }
  538. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  539. unsigned char *pImage = (unsigned char *)lockedRect.pBits;
  540. // garymcthack : need to make a recording command for this.
  541. ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
  542. pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedRect.Pitch );
  543. #ifndef RECORD_TEXTURES
  544. RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
  545. RECORD_INT( info.m_TextureHandle );
  546. RECORD_INT( info.m_nCopy );
  547. RECORD_INT( info.m_nLevel );
  548. RECORD_INT( info.m_CubeFaceID );
  549. #endif
  550. if ( FAILED( pTextureLevel->UnlockRect() ) )
  551. {
  552. Warning( "CShaderAPIDX8::BlitTextureBits: couldn't unlock texture rect\n" );
  553. pTextureLevel->Release();
  554. return;
  555. }
  556. pTextureLevel->Release();
  557. }
  558. #endif
  559. //-----------------------------------------------------------------------------
  560. // Puts 2D texture data into 360 gpu memory.
  561. //-----------------------------------------------------------------------------
  562. #if defined( _X360 )
  563. static void BlitSurfaceBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  564. {
  565. // xbox textures are NOT backed in gpu memory contiguously
  566. // stride details are critical - see [Xbox 360 Texture Storage]
  567. // a d3dformat identifier on the xbox is tiled, the same d3dformat on the pc is expected linear to the app
  568. // we purposely hide the tiling here, otherwise much confusion for the pc
  569. // the *entire* target must be un-tiled *only* before any *subrect* blitting linear work
  570. // the *entire* target must then be re-tiled after the *subrect* blit
  571. // procedural textures require this to subrect blit their new portions correctly
  572. // the tiling dance can be avoided if the source and target match in tiled state during a full rect blit
  573. if ( info.m_nLevel == 0 && !g_TextureHeap.IsBaseAllocated( info.m_pTexture ) )
  574. {
  575. return;
  576. }
  577. if ( info.m_bSrcIsTiled )
  578. {
  579. // not supporting subrect blitting from a tiled source
  580. Assert( 0 );
  581. return;
  582. }
  583. CUtlBuffer formatConvertMemory;
  584. unsigned char *pSrcData = info.m_pSrcData;
  585. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  586. if ( dstFormat != info.m_SrcFormat )
  587. {
  588. if ( !info.m_bCanConvertFormat )
  589. {
  590. // texture is expected to be in target format
  591. // not supporting conversion of a tiled source
  592. Assert( 0 );
  593. return;
  594. }
  595. int srcSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, info.m_SrcFormat, false );
  596. int dstSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, dstFormat, false );
  597. formatConvertMemory.EnsureCapacity( dstSize );
  598. // due to format conversion, source is in non-native order
  599. ImageLoader::PreConvertSwapImageData( (unsigned char*)info.m_pSrcData, srcSize, info.m_SrcFormat, VTF_CONSOLE_360, info.m_nWidth, srcStride );
  600. // slow conversion operation
  601. if ( !ShaderUtil()->ConvertImageFormat(
  602. info.m_pSrcData,
  603. info.m_SrcFormat,
  604. (unsigned char*)formatConvertMemory.Base(),
  605. dstFormat,
  606. info.m_nWidth,
  607. info.m_nHeight,
  608. srcStride,
  609. 0 ) )
  610. {
  611. // conversion failed
  612. Assert( 0 );
  613. return;
  614. }
  615. // due to format conversion, source must have been in non-native order
  616. ImageLoader::PostConvertSwapImageData( (unsigned char*)formatConvertMemory.Base(), dstSize, dstFormat, VTF_CONSOLE_360 );
  617. pSrcData = (unsigned char*)formatConvertMemory.Base();
  618. }
  619. // get the top mip level info (needed for proper sub mip access)
  620. XGTEXTURE_DESC baseDesc;
  621. XGGetTextureDesc( info.m_pTexture, 0, &baseDesc );
  622. bool bDstIsTiled = XGIsTiledFormat( baseDesc.Format ) == TRUE;
  623. // get the target mip level info
  624. XGTEXTURE_DESC mipDesc;
  625. XGGetTextureDesc( info.m_pTexture, info.m_nLevel, &mipDesc );
  626. bool bFullSurfBlit = ( mipDesc.Width == (unsigned)info.m_nWidth && mipDesc.Height == (unsigned)info.m_nHeight );
  627. // get the mip level of the texture we want to write into
  628. IDirect3DSurface* pTextureLevel = NULL;
  629. unsigned char *pTargetImage;
  630. if ( info.m_nLevel == 0 )
  631. {
  632. // can bypass API to gain pointer, circumventing a D3DRIP when async texture streaming
  633. pTargetImage = (unsigned char *)GetD3DTextureBasePtr( info.m_pTexture );
  634. // textures can have a non-zero offset due to texture tiles
  635. pTargetImage += XGGetMipLevelOffset( info.m_pTexture, info.m_CubeFaceID, 0 );
  636. }
  637. else
  638. {
  639. // using API to avoid determining true mip bases
  640. // texture streaming does not blat in mips, so no D3DRIP
  641. HRESULT hr = GetSurfaceFromTexture( info.m_pTexture, info.m_nLevel, info.m_CubeFaceID, &pTextureLevel );
  642. if ( FAILED( hr ) )
  643. {
  644. Warning( "CShaderAPIDX8::BlitSurfaceBits: GetSurfaceFromTexture() failure\n" );
  645. return;
  646. }
  647. D3DLOCKED_RECT lockedRect;
  648. hr = pTextureLevel->LockRect( &lockedRect, NULL, D3DLOCK_NOSYSLOCK );
  649. if ( FAILED( hr ) )
  650. {
  651. Warning( "CShaderAPIDX8::BlitSurfaceBits: couldn't lock texture rect\n" );
  652. pTextureLevel->Release();
  653. return;
  654. }
  655. pTargetImage = (unsigned char *)lockedRect.pBits;
  656. }
  657. POINT p;
  658. p.x = xOffset;
  659. p.y = yOffset;
  660. RECT r;
  661. r.left = 0;
  662. r.top = 0;
  663. r.right = info.m_nWidth;
  664. r.bottom = info.m_nHeight;
  665. int blockSize = mipDesc.Width/mipDesc.WidthInBlocks;
  666. if ( !srcStride )
  667. {
  668. srcStride = (mipDesc.Width/blockSize)*mipDesc.BytesPerBlock;
  669. }
  670. // subrect blitting path
  671. if ( !bDstIsTiled )
  672. {
  673. // Copy the subrect without conversion
  674. HRESULT hr = XGCopySurface(
  675. pTargetImage,
  676. mipDesc.RowPitch,
  677. mipDesc.Width,
  678. mipDesc.Height,
  679. mipDesc.Format,
  680. &p,
  681. pSrcData,
  682. srcStride,
  683. mipDesc.Format,
  684. &r,
  685. 0,
  686. 0 );
  687. if ( FAILED( hr ) )
  688. {
  689. Warning( "CShaderAPIDX8::BlitSurfaceBits: failed subrect copy\n" );
  690. }
  691. }
  692. else
  693. {
  694. int tileFlags = 0;
  695. if ( !( mipDesc.Flags & XGTDESC_PACKED ) )
  696. tileFlags |= XGTILE_NONPACKED;
  697. if ( mipDesc.Flags & XGTDESC_BORDERED )
  698. tileFlags |= XGTILE_BORDER;
  699. // tile the temp store back into the target surface
  700. XGTileTextureLevel(
  701. baseDesc.Width,
  702. baseDesc.Height,
  703. info.m_nLevel,
  704. XGGetGpuFormat( baseDesc.Format ),
  705. tileFlags,
  706. pTargetImage,
  707. &p,
  708. pSrcData,
  709. srcStride,
  710. &r );
  711. }
  712. if ( pTextureLevel )
  713. {
  714. pTextureLevel->UnlockRect();
  715. pTextureLevel->Release();
  716. }
  717. }
  718. #endif
  719. #if defined( _PS3 )
  720. static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  721. {
  722. if ( xOffset || yOffset || /*info.m_nZOffset ||*/ srcStride )
  723. {
  724. // not supporting any subvolume blitting
  725. // the entire volume per mip must be blitted
  726. Assert( 0 );
  727. return;
  728. }
  729. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  730. if ( dstFormat != info.m_SrcFormat )
  731. {
  732. // texture is expected to be in target format
  733. // not supporting conversion
  734. Assert( 0 );
  735. return;
  736. }
  737. D3DBOX srcBox;
  738. D3DLOCKED_BOX lockedBox;
  739. srcBox.Left = xOffset;
  740. srcBox.Right = xOffset + info.m_nWidth;
  741. srcBox.Top = yOffset;
  742. srcBox.Bottom = yOffset + info.m_nHeight;
  743. srcBox.Front = 0;
  744. srcBox.Back = info.m_nZOffset; // doesn't matter, locking entire texture effectively
  745. #ifndef RECORD_TEXTURES
  746. RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
  747. RECORD_INT( info.m_TextureHandle );
  748. RECORD_INT( info.m_nCopy );
  749. RECORD_INT( info.m_nLevel );
  750. RECORD_INT( info.m_CubeFaceID );
  751. RECORD_STRUCT( &srcRect, sizeof(srcRect) );
  752. RECORD_INT( D3DLOCK_NOSYSLOCK );
  753. #endif
  754. IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
  755. if ( FAILED( pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, &srcBox, D3DLOCK_NOSYSLOCK ) ) )
  756. {
  757. Warning( "BlitVolumeBits: couldn't lock volume texture rect\n" );
  758. return;
  759. }
  760. // <vitaliy> blast the bits straight into local memory
  761. unsigned char *pImage = (unsigned char *)lockedBox.pBits;
  762. size_t numBytes = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, info.m_nZOffset, dstFormat, false );
  763. memcpy( pImage, info.m_pSrcData, numBytes );
  764. #ifndef RECORD_TEXTURES
  765. RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
  766. RECORD_INT( info.m_TextureHandle );
  767. RECORD_INT( info.m_nCopy );
  768. RECORD_INT( info.m_nLevel );
  769. RECORD_INT( info.m_CubeFaceID );
  770. #endif
  771. if ( FAILED( pVolumeTexture->UnlockBox( info.m_nLevel ) ) )
  772. {
  773. Warning( "BlitVolumeBits: couldn't unlock volume texture rect\n" );
  774. return;
  775. }
  776. }
  777. #endif
  778. //-----------------------------------------------------------------------------
  779. // Blit in bits
  780. //-----------------------------------------------------------------------------
  781. #if !defined( _X360 ) && !defined( _PS3 )
  782. static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  783. {
  784. D3DBOX srcBox;
  785. D3DLOCKED_BOX lockedBox;
  786. srcBox.Left = xOffset;
  787. srcBox.Right = xOffset + info.m_nWidth;
  788. srcBox.Top = yOffset;
  789. srcBox.Bottom = yOffset + info.m_nHeight;
  790. srcBox.Front = info.m_nZOffset;
  791. srcBox.Back = info.m_nZOffset + 1;
  792. #ifndef RECORD_TEXTURES
  793. RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
  794. RECORD_INT( info.m_TextureHandle );
  795. RECORD_INT( info.m_nCopy );
  796. RECORD_INT( info.m_nLevel );
  797. RECORD_INT( info.m_CubeFaceID );
  798. RECORD_STRUCT( &srcRect, sizeof(srcRect) );
  799. RECORD_INT( D3DLOCK_NOSYSLOCK );
  800. #endif
  801. IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
  802. if ( FAILED( pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, &srcBox, D3DLOCK_NOSYSLOCK ) ) )
  803. {
  804. Warning( "BlitVolumeBits: couldn't lock volume texture rect\n" );
  805. return;
  806. }
  807. // garymcthack : need to make a recording command for this.
  808. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  809. unsigned char *pImage = (unsigned char *)lockedBox.pBits;
  810. ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
  811. pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedBox.RowPitch );
  812. #ifndef RECORD_TEXTURES
  813. RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
  814. RECORD_INT( info.m_TextureHandle );
  815. RECORD_INT( info.m_nCopy );
  816. RECORD_INT( info.m_nLevel );
  817. RECORD_INT( info.m_CubeFaceID );
  818. #endif
  819. if ( FAILED( pVolumeTexture->UnlockBox( info.m_nLevel ) ) )
  820. {
  821. Warning( "BlitVolumeBits: couldn't unlock volume texture rect\n" );
  822. return;
  823. }
  824. }
  825. #endif
  826. //-----------------------------------------------------------------------------
  827. // Puts 3D texture data into 360 gpu memory.
  828. // Does not support any subvolume or slice blitting.
  829. //-----------------------------------------------------------------------------
  830. #if defined( _X360 )
  831. static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  832. {
  833. if ( xOffset || yOffset || info.m_nZOffset || srcStride )
  834. {
  835. // not supporting any subvolume blitting
  836. // the entire volume per mip must be blitted
  837. Assert( 0 );
  838. return;
  839. }
  840. ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
  841. if ( dstFormat != info.m_SrcFormat )
  842. {
  843. // texture is expected to be in target format
  844. // not supporting conversion
  845. Assert( 0 );
  846. return;
  847. }
  848. // get the top mip level info (needed for proper sub mip access)
  849. XGTEXTURE_DESC baseDesc;
  850. XGGetTextureDesc( info.m_pTexture, 0, &baseDesc );
  851. bool bDstIsTiled = XGIsTiledFormat( baseDesc.Format ) == TRUE;
  852. if ( info.m_bSrcIsTiled && !bDstIsTiled )
  853. {
  854. // not supporting a tiled source into an untiled target
  855. Assert( 0 );
  856. return;
  857. }
  858. // get the mip level info
  859. XGTEXTURE_DESC mipDesc;
  860. XGGetTextureDesc( info.m_pTexture, info.m_nLevel, &mipDesc );
  861. bool bFullSurfBlit = ( mipDesc.Width == (unsigned int)info.m_nWidth && mipDesc.Height == (unsigned int)info.m_nHeight );
  862. if ( !bFullSurfBlit )
  863. {
  864. // not supporting subrect blitting
  865. Assert( 0 );
  866. return;
  867. }
  868. D3DLOCKED_BOX lockedBox;
  869. // get the mip level of the volume we want to write into
  870. IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
  871. HRESULT hr = pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, NULL, D3DLOCK_NOSYSLOCK );
  872. if ( FAILED( hr ) )
  873. {
  874. Warning( "CShaderAPIDX8::BlitVolumeBits: Couldn't lock volume box\n" );
  875. return;
  876. }
  877. unsigned char *pSrcData = info.m_pSrcData;
  878. unsigned char *pTargetImage = (unsigned char *)lockedBox.pBits;
  879. int tileFlags = 0;
  880. if ( !( mipDesc.Flags & XGTDESC_PACKED ) )
  881. tileFlags |= XGTILE_NONPACKED;
  882. if ( mipDesc.Flags & XGTDESC_BORDERED )
  883. tileFlags |= XGTILE_BORDER;
  884. if ( !info.m_bSrcIsTiled && bDstIsTiled )
  885. {
  886. // tile the source directly into the target surface
  887. XGTileVolumeTextureLevel(
  888. baseDesc.Width,
  889. baseDesc.Height,
  890. baseDesc.Depth,
  891. info.m_nLevel,
  892. XGGetGpuFormat( baseDesc.Format ),
  893. tileFlags,
  894. pTargetImage,
  895. NULL,
  896. pSrcData,
  897. mipDesc.RowPitch,
  898. mipDesc.SlicePitch,
  899. NULL );
  900. }
  901. else if ( !info.m_bSrcIsTiled && !bDstIsTiled )
  902. {
  903. // not implemented yet
  904. Assert( 0 );
  905. }
  906. else
  907. {
  908. // not implemented yet
  909. Assert( 0 );
  910. }
  911. hr = pVolumeTexture->UnlockBox( info.m_nLevel );
  912. if ( FAILED( hr ) )
  913. {
  914. Warning( "CShaderAPIDX8::BlitVolumeBits: couldn't unlock volume box\n" );
  915. return;
  916. }
  917. }
  918. #endif
  919. // 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.
  920. // 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.
  921. // 6) LockRects should be used for copying between SYSTEMMEM and
  922. // MANAGED. For such a small copy, you'd avoid a significant
  923. // amount of overhead from the old CopyRects code. Ideally, you
  924. // should just lock the bottom of MANAGED and generate your
  925. // sub-4x4 data there.
  926. // NOTE: IF YOU CHANGE THIS, CHANGE THE VERSION IN PLAYBACK.CPP!!!!
  927. static void BlitTextureBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  928. {
  929. #ifdef RECORD_TEXTURES
  930. RECORD_COMMAND( DX8_BLIT_TEXTURE_BITS, 14 );
  931. RECORD_INT( info.m_TextureHandle );
  932. RECORD_INT( info.m_nCopy );
  933. RECORD_INT( info.m_nLevel );
  934. RECORD_INT( info.m_CubeFaceID );
  935. RECORD_INT( xOffset );
  936. RECORD_INT( yOffset );
  937. RECORD_INT( info.m_nZOffset );
  938. RECORD_INT( info.m_nWidth );
  939. RECORD_INT( info.m_nHeight );
  940. RECORD_INT( info.m_SrcFormat );
  941. RECORD_INT( srcStride );
  942. RECORD_INT( GetImageFormat( info.m_pTexture ) );
  943. // strides are in bytes.
  944. int srcDataSize;
  945. if ( srcStride == 0 )
  946. {
  947. srcDataSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, info.m_SrcFormat, false );
  948. }
  949. else
  950. {
  951. srcDataSize = srcStride * info.m_nHeight;
  952. }
  953. RECORD_INT( srcDataSize );
  954. RECORD_STRUCT( info.m_pSrcData, srcDataSize );
  955. #endif // RECORD_TEXTURES
  956. if ( !IsVolumeTexture( info.m_pTexture ) )
  957. {
  958. Assert( info.m_nZOffset == 0 );
  959. BlitSurfaceBits( info, xOffset, yOffset, srcStride );
  960. }
  961. else
  962. {
  963. BlitVolumeBits( info, xOffset, yOffset, srcStride );
  964. }
  965. }
  966. //-----------------------------------------------------------------------------
  967. // Texture image upload
  968. //-----------------------------------------------------------------------------
  969. void LoadTexture( TextureLoadInfo_t &info )
  970. {
  971. MEM_ALLOC_D3D_CREDIT();
  972. Assert( info.m_pSrcData );
  973. Assert( info.m_pTexture );
  974. #ifdef _DEBUG
  975. ImageFormat format = GetImageFormat( info.m_pTexture );
  976. Assert( (format != -1) && (format == ImageLoader::D3DFormatToImageFormat( FindNearestSupportedFormat( format, false, false, false )) ) );
  977. #endif
  978. // Copy in the bits...
  979. BlitTextureBits( info, 0, 0, 0 );
  980. }
  981. //-----------------------------------------------------------------------------
  982. // Upload to a sub-piece of a texture
  983. //-----------------------------------------------------------------------------
  984. void LoadSubTexture( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
  985. {
  986. Assert( info.m_pSrcData );
  987. Assert( info.m_pTexture );
  988. #if defined( _X360 )
  989. // xboxissue - not supporting subrect swizzling
  990. Assert( !info.m_bSrcIsTiled );
  991. #endif
  992. #ifdef _DEBUG
  993. ImageFormat format = GetImageFormat( info.m_pTexture );
  994. Assert( (format == ImageLoader::D3DFormatToImageFormat( FindNearestSupportedFormat(format, false, false, false )) ) && (format != -1) );
  995. #endif
  996. // Copy in the bits...
  997. BlitTextureBits( info, xOffset, yOffset, srcStride );
  998. }
  999. //-----------------------------------------------------------------------------
  1000. // Returns the size of texture memory, in MB
  1001. //-----------------------------------------------------------------------------
  1002. // Helps with startup time.. we don't use the texture memory size for anything anyways
  1003. #define DONT_CHECK_MEM
  1004. int ComputeTextureMemorySize( const GUID &nDeviceGUID, D3DDEVTYPE deviceType )
  1005. {
  1006. #if !defined( _X360 )
  1007. FileHandle_t file = g_pFullFileSystem->Open( "vidcfg.bin", "rb", "EXECUTABLE_PATH" );
  1008. if ( file )
  1009. {
  1010. GUID deviceId;
  1011. int texSize;
  1012. g_pFullFileSystem->Read( &deviceId, sizeof(deviceId), file );
  1013. g_pFullFileSystem->Read( &texSize, sizeof(texSize), file );
  1014. g_pFullFileSystem->Close( file );
  1015. if ( nDeviceGUID == deviceId )
  1016. {
  1017. return texSize;
  1018. }
  1019. }
  1020. // How much texture memory?
  1021. if (deviceType == D3DDEVTYPE_REF)
  1022. return 64 * 1024 * 1024;
  1023. // Sadly, the only way to compute texture memory size
  1024. // is to allocate a crapload of textures until we can't any more
  1025. ImageFormat fmt = ImageLoader::D3DFormatToImageFormat( FindNearestSupportedFormat( IMAGE_FORMAT_BGR565, false, false, false ) );
  1026. int textureSize = ShaderUtil()->GetMemRequired( 256, 256, 1, fmt, false );
  1027. int totalSize = 0;
  1028. CUtlVector< IDirect3DBaseTexture* > textures;
  1029. #ifndef DONT_CHECK_MEM
  1030. while (true)
  1031. {
  1032. RECORD_COMMAND( DX8_CREATE_TEXTURE, 7 );
  1033. RECORD_INT( textures.Count() );
  1034. RECORD_INT( 256 );
  1035. RECORD_INT( 256 );
  1036. RECORD_INT( ImageLoader::ImageFormatToD3DFormat(fmt) );
  1037. RECORD_INT( 1 );
  1038. RECORD_INT( false );
  1039. RECORD_INT( 1 );
  1040. IDirect3DBaseTexture* pTex = CreateD3DTexture( 256, 256, 1, fmt, 1, 0 );
  1041. if (!pTex)
  1042. break;
  1043. totalSize += textureSize;
  1044. textures.AddToTail( pTex );
  1045. }
  1046. // Free all the temp textures
  1047. for (int i = textures.Size(); --i >= 0; )
  1048. {
  1049. RECORD_COMMAND( DX8_DESTROY_TEXTURE, 1 );
  1050. RECORD_INT( i );
  1051. DestroyD3DTexture( textures[i] );
  1052. }
  1053. #else
  1054. totalSize = 102236160;
  1055. #endif
  1056. file = g_pFullFileSystem->Open( "vidcfg.bin", "wb", "EXECUTABLE_PATH" );
  1057. if ( file )
  1058. {
  1059. g_pFullFileSystem->Write( &nDeviceGUID, sizeof(GUID), file );
  1060. g_pFullFileSystem->Write( &totalSize, sizeof(totalSize), file );
  1061. g_pFullFileSystem->Close( file );
  1062. }
  1063. return totalSize;
  1064. #else
  1065. return 0;
  1066. #endif
  1067. }