summaryrefslogtreecommitdiff
path: root/materialsystem/shaderapidx9/texturedx8.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /materialsystem/shaderapidx9/texturedx8.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'materialsystem/shaderapidx9/texturedx8.cpp')
-rw-r--r--materialsystem/shaderapidx9/texturedx8.cpp1545
1 files changed, 1545 insertions, 0 deletions
diff --git a/materialsystem/shaderapidx9/texturedx8.cpp b/materialsystem/shaderapidx9/texturedx8.cpp
new file mode 100644
index 0000000..d4dbede
--- /dev/null
+++ b/materialsystem/shaderapidx9/texturedx8.cpp
@@ -0,0 +1,1545 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#define DISABLE_PROTECTED_THINGS
+#include "locald3dtypes.h"
+#include "texturedx8.h"
+#include "shaderapidx8_global.h"
+#include "colorformatdx8.h"
+#include "shaderapi/ishaderutil.h"
+#include "materialsystem/imaterialsystem.h"
+#include "utlvector.h"
+#include "recording.h"
+#include "shaderapi/ishaderapi.h"
+#include "filesystem.h"
+#include "locald3dtypes.h"
+#include "textureheap.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/callqueue.h"
+#include "tier0/vprof.h"
+#include "vtf/vtf.h"
+#include "tier0/icommandline.h"
+
+#include "tier0/memdbgon.h"
+
+#ifdef _WIN32
+#pragma warning (disable:4189 4701)
+#endif
+
+static int s_TextureCount = 0;
+static bool s_bTestingVideoMemorySize = false;
+
+//-----------------------------------------------------------------------------
+// Stats...
+//-----------------------------------------------------------------------------
+
+int TextureCount()
+{
+ return s_TextureCount;
+}
+
+static bool IsVolumeTexture( IDirect3DBaseTexture* pBaseTexture )
+{
+ if ( !pBaseTexture )
+ {
+ return false;
+ }
+
+ return ( pBaseTexture->GetType() == D3DRTYPE_VOLUMETEXTURE );
+}
+
+static HRESULT GetLevelDesc( IDirect3DBaseTexture* pBaseTexture, UINT level, D3DSURFACE_DESC* pDesc )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( !pBaseTexture )
+ {
+ return ( HRESULT )-1;
+ }
+
+ HRESULT hr;
+ switch( pBaseTexture->GetType() )
+ {
+ case D3DRTYPE_TEXTURE:
+ hr = ( ( IDirect3DTexture * )pBaseTexture )->GetLevelDesc( level, pDesc );
+ break;
+ case D3DRTYPE_CUBETEXTURE:
+ hr = ( ( IDirect3DCubeTexture * )pBaseTexture )->GetLevelDesc( level, pDesc );
+ break;
+ default:
+ return ( HRESULT )-1;
+ }
+ return hr;
+}
+
+static HRESULT GetSurfaceFromTexture( IDirect3DBaseTexture* pBaseTexture, UINT level,
+ D3DCUBEMAP_FACES cubeFaceID, IDirect3DSurface** ppSurfLevel )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( !pBaseTexture )
+ {
+ return ( HRESULT )-1;
+ }
+
+ HRESULT hr;
+
+ switch( pBaseTexture->GetType() )
+ {
+ case D3DRTYPE_TEXTURE:
+ hr = ( ( IDirect3DTexture * )pBaseTexture )->GetSurfaceLevel( level, ppSurfLevel );
+ break;
+ case D3DRTYPE_CUBETEXTURE:
+ if (cubeFaceID !=0)
+ {
+ //Debugger();
+ }
+
+ hr = ( ( IDirect3DCubeTexture * )pBaseTexture )->GetCubeMapSurface( cubeFaceID, level, ppSurfLevel );
+ break;
+ default:
+ Assert(0);
+ return ( HRESULT )-1;
+ }
+ return hr;
+}
+
+//-----------------------------------------------------------------------------
+// Gets the image format of a texture
+//-----------------------------------------------------------------------------
+static ImageFormat GetImageFormat( IDirect3DBaseTexture* pTexture )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( pTexture )
+ {
+ HRESULT hr;
+ if ( !IsVolumeTexture( pTexture ) )
+ {
+ D3DSURFACE_DESC desc;
+ hr = GetLevelDesc( pTexture, 0, &desc );
+ if ( !FAILED( hr ) )
+ return ImageLoader::D3DFormatToImageFormat( desc.Format );
+ }
+ else
+ {
+ D3DVOLUME_DESC desc;
+ IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( pTexture );
+ hr = pVolumeTexture->GetLevelDesc( 0, &desc );
+ if ( !FAILED( hr ) )
+ return ImageLoader::D3DFormatToImageFormat( desc.Format );
+ }
+ }
+
+ // Bogus baby!
+ return (ImageFormat)-1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Allocates the D3DTexture
+//-----------------------------------------------------------------------------
+IDirect3DBaseTexture* CreateD3DTexture( int width, int height, int nDepth,
+ ImageFormat dstFormat, int numLevels, int nCreationFlags, char *debugLabel ) // OK to skip the last param
+{
+ if ( nDepth <= 0 )
+ {
+ nDepth = 1;
+ }
+
+ bool isCubeMap = ( nCreationFlags & TEXTURE_CREATE_CUBEMAP ) != 0;
+ bool bIsRenderTarget = ( nCreationFlags & TEXTURE_CREATE_RENDERTARGET ) != 0;
+ bool bManaged = ( nCreationFlags & TEXTURE_CREATE_MANAGED ) != 0;
+ bool bSysmem = ( nCreationFlags & TEXTURE_CREATE_SYSMEM ) != 0;
+ bool bIsDepthBuffer = ( nCreationFlags & TEXTURE_CREATE_DEPTHBUFFER ) != 0;
+ bool isDynamic = ( nCreationFlags & TEXTURE_CREATE_DYNAMIC ) != 0;
+ bool bAutoMipMap = ( nCreationFlags & TEXTURE_CREATE_AUTOMIPMAP ) != 0;
+ bool bVertexTexture = ( nCreationFlags & TEXTURE_CREATE_VERTEXTEXTURE ) != 0;
+ bool bAllowNonFilterable = ( nCreationFlags & TEXTURE_CREATE_UNFILTERABLE_OK ) != 0;
+ bool bVolumeTexture = ( nDepth > 1 );
+ bool bIsFallback = ( nCreationFlags & TEXTURE_CREATE_FALLBACK ) != 0;
+ bool bNoD3DBits = ( nCreationFlags & TEXTURE_CREATE_NOD3DMEMORY ) != 0;
+ bool bSRGB = (nCreationFlags & TEXTURE_CREATE_SRGB) != 0; // for Posix/GL only
+
+ // NOTE: This function shouldn't be used for creating depth buffers!
+ Assert( !bIsDepthBuffer );
+
+ D3DFORMAT d3dFormat = D3DFMT_UNKNOWN;
+
+ D3DPOOL pool = bManaged ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT;
+ if ( bSysmem )
+ pool = D3DPOOL_SYSTEMMEM;
+
+ if ( IsX360() )
+ {
+ // 360 does not support vertex textures
+ // 360 render target creation path is for the target as a texture source (NOT the EDRAM version)
+ // use normal texture format rules
+ Assert( !bVertexTexture );
+ if ( !bVertexTexture )
+ {
+ d3dFormat = ImageLoader::ImageFormatToD3DFormat( FindNearestSupportedFormat( dstFormat, false, false, false ) );
+ }
+ }
+ else
+ {
+ d3dFormat = ImageLoader::ImageFormatToD3DFormat( FindNearestSupportedFormat( dstFormat, bVertexTexture, bIsRenderTarget, bAllowNonFilterable ) );
+ }
+
+ if ( d3dFormat == D3DFMT_UNKNOWN )
+ {
+ Warning( "ShaderAPIDX8::CreateD3DTexture: Invalid color format!\n" );
+ Assert( 0 );
+ return 0;
+ }
+
+ IDirect3DBaseTexture* pBaseTexture = NULL;
+ IDirect3DTexture* pD3DTexture = NULL;
+ IDirect3DCubeTexture* pD3DCubeTexture = NULL;
+ IDirect3DVolumeTexture* pD3DVolumeTexture = NULL;
+ HRESULT hr = S_OK;
+ DWORD usage = 0;
+
+ if ( bIsRenderTarget )
+ {
+ usage |= D3DUSAGE_RENDERTARGET;
+ }
+ if ( isDynamic )
+ {
+ usage |= D3DUSAGE_DYNAMIC;
+ }
+ if ( bAutoMipMap )
+ {
+ usage |= D3DUSAGE_AUTOGENMIPMAP;
+ }
+
+#ifdef DX_TO_GL_ABSTRACTION
+ {
+ if (bSRGB)
+ {
+ usage |= D3DUSAGE_TEXTURE_SRGB; // does not exist in real DX9... just for GL to know that this is an SRGB tex
+ }
+ }
+#endif
+
+ if ( isCubeMap )
+ {
+#if !defined( _X360 )
+ hr = Dx9Device()->CreateCubeTexture(
+ width,
+ numLevels,
+ usage,
+ d3dFormat,
+ pool,
+ &pD3DCubeTexture,
+ NULL
+ #if defined( DX_TO_GL_ABSTRACTION )
+ , debugLabel // tex create funcs take extra arg for debug name on GL
+ #endif
+ );
+#else
+ pD3DCubeTexture = g_TextureHeap.AllocCubeTexture( width, numLevels, usage, d3dFormat, bIsFallback, bNoD3DBits );
+#endif
+ pBaseTexture = pD3DCubeTexture;
+ }
+ else if ( bVolumeTexture )
+ {
+#if !defined( _X360 )
+ hr = Dx9Device()->CreateVolumeTexture(
+ width,
+ height,
+ nDepth,
+ numLevels,
+ usage,
+ d3dFormat,
+ pool,
+ &pD3DVolumeTexture,
+ NULL
+ #if defined( DX_TO_GL_ABSTRACTION )
+ , debugLabel // tex create funcs take extra arg for debug name on GL
+ #endif
+ );
+#else
+ Assert( !bIsFallback && !bNoD3DBits );
+ pD3DVolumeTexture = g_TextureHeap.AllocVolumeTexture( width, height, nDepth, numLevels, usage, d3dFormat );
+#endif
+ pBaseTexture = pD3DVolumeTexture;
+ }
+ else
+ {
+#if !defined( _X360 )
+ // Override usage and managed params if using special hardware shadow depth map formats...
+ if ( ( d3dFormat == NVFMT_RAWZ ) || ( d3dFormat == NVFMT_INTZ ) ||
+ ( d3dFormat == D3DFMT_D16 ) || ( d3dFormat == D3DFMT_D24S8 ) ||
+ ( d3dFormat == ATIFMT_D16 ) || ( d3dFormat == ATIFMT_D24S8 ) )
+ {
+ // Not putting D3DUSAGE_RENDERTARGET here causes D3D debug spew later, but putting the flag causes this create to fail...
+ usage = D3DUSAGE_DEPTHSTENCIL;
+ bManaged = false;
+ }
+
+ // Override managed param if using special null texture format
+ if ( d3dFormat == NVFMT_NULL )
+ {
+ bManaged = false;
+ }
+
+ hr = Dx9Device()->CreateTexture(
+ width,
+ height,
+ numLevels,
+ usage,
+ d3dFormat,
+ pool,
+ &pD3DTexture,
+ NULL
+ #if defined( DX_TO_GL_ABSTRACTION )
+ , debugLabel // tex create funcs take extra arg for debug name on GL
+ #endif
+ );
+
+#else
+ pD3DTexture = g_TextureHeap.AllocTexture( width, height, numLevels, usage, d3dFormat, bIsFallback, bNoD3DBits );
+#endif
+ pBaseTexture = pD3DTexture;
+ }
+
+ if ( FAILED( hr ) )
+ {
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ if( CommandLine()->FindParm( "-nulldevice" ) )
+ {
+ Warning( "ShaderAPIDX8::CreateD3DTexture: Null device used. Texture not created.\n" );
+ return 0;
+ }
+#endif
+
+ switch ( hr )
+ {
+ case D3DERR_INVALIDCALL:
+ Warning( "ShaderAPIDX8::CreateD3DTexture: D3DERR_INVALIDCALL\n" );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ // This conditional is here so that we don't complain when testing
+ // how much video memory we have. . this is kinda gross.
+ if ( !s_bTestingVideoMemorySize )
+ {
+ Warning( "ShaderAPIDX8::CreateD3DTexture: D3DERR_OUTOFVIDEOMEMORY\n" );
+ }
+ break;
+ case E_OUTOFMEMORY:
+ Warning( "ShaderAPIDX8::CreateD3DTexture: E_OUTOFMEMORY\n" );
+ break;
+ default:
+ break;
+ }
+ return 0;
+ }
+
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ int nMipCount = numLevels;
+ if ( !nMipCount )
+ {
+ while ( width > 1 || height > 1 )
+ {
+ width >>= 1;
+ height >>= 1;
+ ++nMipCount;
+ }
+ }
+
+ int nMemUsed = nMipCount * 1.1f * 1024;
+ if ( isCubeMap )
+ {
+ nMemUsed *= 6;
+ }
+
+ VPROF_INCREMENT_GROUP_COUNTER( "texture count", COUNTER_GROUP_NO_RESET, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "texture driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+#endif
+
+ ++s_TextureCount;
+
+ return pBaseTexture;
+}
+
+
+//-----------------------------------------------------------------------------
+// Texture destruction
+//-----------------------------------------------------------------------------
+void ReleaseD3DTexture( IDirect3DBaseTexture* pD3DTex )
+{
+ int ref = pD3DTex->Release();
+ Assert( ref == 0 );
+}
+
+void DestroyD3DTexture( IDirect3DBaseTexture* pD3DTex )
+{
+ if ( pD3DTex )
+ {
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ D3DRESOURCETYPE type = pD3DTex->GetType();
+ int nMipCount = pD3DTex->GetLevelCount();
+ if ( type == D3DRTYPE_CUBETEXTURE )
+ {
+ nMipCount *= 6;
+ }
+ int nMemUsed = nMipCount * 1.1f * 1024;
+ VPROF_INCREMENT_GROUP_COUNTER( "texture count", COUNTER_GROUP_NO_RESET, -1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "texture driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+#endif
+
+#if !defined( _X360 )
+ CMatRenderContextPtr pRenderContext( materials );
+ ICallQueue *pCallQueue;
+ if ( ( pCallQueue = pRenderContext->GetCallQueue() ) != NULL )
+ {
+ pCallQueue->QueueCall( ReleaseD3DTexture, pD3DTex );
+ }
+ else
+ {
+ ReleaseD3DTexture( pD3DTex );
+ }
+#else
+ g_TextureHeap.FreeTexture( pD3DTex );
+#endif
+ --s_TextureCount;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pTex -
+// Output : int
+//-----------------------------------------------------------------------------
+int GetD3DTextureRefCount( IDirect3DBaseTexture *pTex )
+{
+ if ( !pTex )
+ return 0;
+
+ pTex->AddRef();
+ int ref = pTex->Release();
+
+ return ref;
+}
+
+//-----------------------------------------------------------------------------
+// See version 13 for a function that converts a texture to a mipmap (ConvertToMipmap)
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Lock, unlock a texture...
+//-----------------------------------------------------------------------------
+
+static RECT s_LockedSrcRect;
+static D3DLOCKED_RECT s_LockedRect;
+#ifdef DBGFLAG_ASSERT
+static bool s_bInLock = false;
+#endif
+
+bool LockTexture( ShaderAPITextureHandle_t bindId, int copy, IDirect3DBaseTexture* pTexture, int level,
+ D3DCUBEMAP_FACES cubeFaceID, int xOffset, int yOffset, int width, int height, bool bDiscard,
+ CPixelWriter& writer )
+{
+ Assert( !s_bInLock );
+
+ IDirect3DSurface* pSurf;
+ HRESULT hr = GetSurfaceFromTexture( pTexture, level, cubeFaceID, &pSurf );
+ if ( FAILED( hr ) )
+ return false;
+
+ s_LockedSrcRect.left = xOffset;
+ s_LockedSrcRect.right = xOffset + width;
+ s_LockedSrcRect.top = yOffset;
+ s_LockedSrcRect.bottom = yOffset + height;
+
+ unsigned int flags = D3DLOCK_NOSYSLOCK;
+ flags |= bDiscard ? D3DLOCK_DISCARD : 0;
+ RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
+ RECORD_INT( bindId );
+ RECORD_INT( copy );
+ RECORD_INT( level );
+ RECORD_INT( cubeFaceID );
+ RECORD_STRUCT( &s_LockedSrcRect, sizeof(s_LockedSrcRect) );
+ RECORD_INT( flags );
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "D3DLockTexture" );
+
+ hr = pSurf->LockRect( &s_LockedRect, &s_LockedSrcRect, flags );
+ pSurf->Release();
+
+ if ( FAILED( hr ) )
+ return false;
+
+ writer.SetPixelMemory( GetImageFormat(pTexture), s_LockedRect.pBits, s_LockedRect.Pitch );
+
+#ifdef DBGFLAG_ASSERT
+ s_bInLock = true;
+#endif
+ return true;
+}
+
+void UnlockTexture( ShaderAPITextureHandle_t bindId, int copy, IDirect3DBaseTexture* pTexture, int level,
+ D3DCUBEMAP_FACES cubeFaceID )
+{
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
+
+ Assert( s_bInLock );
+
+ IDirect3DSurface* pSurf;
+ HRESULT hr = GetSurfaceFromTexture( pTexture, level, cubeFaceID, &pSurf );
+ if (FAILED(hr))
+ return;
+
+#ifdef RECORD_TEXTURES
+ int width = s_LockedSrcRect.right - s_LockedSrcRect.left;
+ int height = s_LockedSrcRect.bottom - s_LockedSrcRect.top;
+ int imageFormatSize = ImageLoader::SizeInBytes( GetImageFormat( pTexture ) );
+ Assert( imageFormatSize != 0 );
+ int validDataBytesPerRow = imageFormatSize * width;
+ int storeSize = validDataBytesPerRow * height;
+ static CUtlVector< unsigned char > tmpMem;
+ if( tmpMem.Size() < storeSize )
+ {
+ tmpMem.AddMultipleToTail( storeSize - tmpMem.Size() );
+ }
+ unsigned char *pDst = tmpMem.Base();
+ unsigned char *pSrc = ( unsigned char * )s_LockedRect.pBits;
+ RECORD_COMMAND( DX8_SET_TEXTURE_DATA, 3 );
+ RECORD_INT( validDataBytesPerRow );
+ RECORD_INT( height );
+ int i;
+ for( i = 0; i < height; i++ )
+ {
+ memcpy( pDst, pSrc, validDataBytesPerRow );
+ pDst += validDataBytesPerRow;
+ pSrc += s_LockedRect.Pitch;
+ }
+ RECORD_STRUCT( tmpMem.Base(), storeSize );
+#endif // RECORD_TEXTURES
+
+ RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
+ RECORD_INT( bindId );
+ RECORD_INT( copy );
+ RECORD_INT( level );
+ RECORD_INT( cubeFaceID );
+
+ hr = pSurf->UnlockRect();
+ pSurf->Release();
+#ifdef DBGFLAG_ASSERT
+ s_bInLock = false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Compute texture size based on compression
+//-----------------------------------------------------------------------------
+
+static inline int DetermineGreaterPowerOfTwo( int val )
+{
+ int num = 1;
+ while (val > num)
+ {
+ num <<= 1;
+ }
+
+ return num;
+}
+
+inline int DeterminePowerOfTwo( int val )
+{
+ int pow = 0;
+ while ((val & 0x1) == 0x0)
+ {
+ val >>= 1;
+ ++pow;
+ }
+
+ return pow;
+}
+
+
+//-----------------------------------------------------------------------------
+// Blit in bits
+//-----------------------------------------------------------------------------
+// NOTE: IF YOU CHANGE THIS, CHANGE THE VERSION IN PLAYBACK.CPP!!!!
+// OPTIMIZE??: could lock the texture directly instead of the surface in dx9.
+#if !defined( _X360 )
+static void BlitSurfaceBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
+
+ // Get the level of the texture we want to write into
+ IDirect3DSurface* pTextureLevel;
+
+ if (info.m_CubeFaceID !=0)
+ {
+ //Debugger();
+ }
+
+
+ HRESULT hr = GetSurfaceFromTexture( info.m_pTexture, info.m_nLevel, info.m_CubeFaceID, &pTextureLevel );
+ if ( FAILED( hr ) )
+ return;
+
+ RECT srcRect;
+ RECT *pSrcRect = NULL;
+ D3DLOCKED_RECT lockedRect;
+
+ srcRect.left = xOffset;
+ srcRect.right = xOffset + info.m_nWidth;
+ srcRect.top = yOffset;
+ srcRect.bottom = yOffset + info.m_nHeight;
+
+#if defined( SHADERAPIDX9 ) && !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ if ( !info.m_bTextureIsLockable )
+ {
+ // Copy from system memory to video memory using D3D9Device->UpdateSurface
+ bool bSuccess = false;
+
+ D3DSURFACE_DESC desc;
+ Verify( pTextureLevel->GetDesc( &desc ) == S_OK );
+ ImageFormat dstFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
+ D3DFORMAT dstFormatD3D = ImageLoader::ImageFormatToD3DFormat( dstFormat );
+
+ IDirect3DSurface* pSrcSurface = NULL;
+ bool bCopyBitsToSrcSurface = true;
+
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
+ // D3D9Ex fast path: create a texture wrapping our own system memory buffer
+ // if the source and destination formats are exactly the same and the stride
+ // is tightly packed. no locking/blitting required.
+ // NOTE: the fast path does not work on sub-4x4 DXT compressed textures.
+ extern bool g_ShaderDeviceUsingD3D9Ex;
+ if ( g_ShaderDeviceUsingD3D9Ex &&
+ ( info.m_SrcFormat == dstFormat || ( info.m_SrcFormat == IMAGE_FORMAT_DXT1_ONEBITALPHA && dstFormat == IMAGE_FORMAT_DXT1 ) ) &&
+ ( !ImageLoader::IsCompressed( dstFormat ) || (info.m_nWidth >= 4 || info.m_nHeight >= 4) ) )
+ {
+ if ( srcStride == 0 || srcStride == info.m_nWidth * ImageLoader::SizeInBytes( info.m_SrcFormat ) )
+ {
+ IDirect3DTexture9* pTempTex = NULL;
+ if ( Dx9Device()->CreateTexture( info.m_nWidth, info.m_nHeight, 1, 0, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempTex, (HANDLE*) &info.m_pSrcData ) == S_OK )
+ {
+ IDirect3DSurface* pTempSurf = NULL;
+ if ( pTempTex->GetSurfaceLevel( 0, &pTempSurf ) == S_OK )
+ {
+ pSrcSurface = pTempSurf;
+ bCopyBitsToSrcSurface = false;
+ }
+ pTempTex->Release();
+ }
+ }
+ }
+#endif
+
+ // If possible to create a texture of this size, create a temporary texture in
+ // system memory and then use the UpdateSurface method to copy between textures.
+ if ( !pSrcSurface && ( g_pHardwareConfig->Caps().m_SupportsNonPow2Textures ||
+ ( IsPowerOfTwo( info.m_nWidth ) && IsPowerOfTwo( info.m_nHeight ) ) ) )
+ {
+ int tempW = info.m_nWidth, tempH = info.m_nHeight, mip = 0;
+ if ( info.m_nLevel > 0 && ( ( tempW | tempH ) & 3 ) && ImageLoader::IsCompressed( dstFormat ) )
+ {
+ // Loading lower mip levels of DXT compressed textures is sort of tricky
+ // because we can't create textures that aren't multiples of 4, and we can't
+ // pass subrectangles of DXT textures into UpdateSurface. Create a temporary
+ // texture which is 1 or 2 mip levels larger and then lock the appropriate
+ // mip level to grab its correctly-dimensioned surface. -henryg 11/18/2011
+ mip = ( info.m_nLevel > 1 && ( ( tempW | tempH ) & 1 ) ) ? 2 : 1;
+ tempW <<= mip;
+ tempH <<= mip;
+ }
+
+ IDirect3DTexture9* pTempTex = NULL;
+ IDirect3DSurface* pTempSurf = NULL;
+ if ( Dx9Device()->CreateTexture( tempW, tempH, mip+1, 0, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempTex, NULL ) == S_OK )
+ {
+ if ( pTempTex->GetSurfaceLevel( mip, &pTempSurf ) == S_OK )
+ {
+ pSrcSurface = pTempSurf;
+ bCopyBitsToSrcSurface = true;
+ }
+ pTempTex->Release();
+ }
+ }
+
+ // Create an offscreen surface if the texture path wasn't an option.
+ if ( !pSrcSurface )
+ {
+ IDirect3DSurface* pTempSurf = NULL;
+ if ( Dx9Device()->CreateOffscreenPlainSurface( info.m_nWidth, info.m_nHeight, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempSurf, NULL ) == S_OK )
+ {
+ pSrcSurface = pTempSurf;
+ bCopyBitsToSrcSurface = true;
+ }
+ }
+
+ // Lock and fill the surface
+ if ( bCopyBitsToSrcSurface && pSrcSurface )
+ {
+ if ( pSrcSurface->LockRect( &lockedRect, NULL, D3DLOCK_NOSYSLOCK ) == S_OK )
+ {
+ unsigned char *pImage = (unsigned char *)lockedRect.pBits;
+ ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
+ pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedRect.Pitch );
+ pSrcSurface->UnlockRect();
+ }
+ else
+ {
+ // Lock failed.
+ pSrcSurface->Release();
+ pSrcSurface = NULL;
+ }
+ }
+
+ // Perform the UpdateSurface call that blits between system and video memory
+ if ( pSrcSurface )
+ {
+ POINT pt = { xOffset, yOffset };
+ bSuccess = ( Dx9Device()->UpdateSurface( pSrcSurface, NULL, pTextureLevel, &pt ) == S_OK );
+ pSrcSurface->Release();
+ }
+
+ if ( !bSuccess )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect or use UpdateSurface\n" );
+ }
+
+ pTextureLevel->Release();
+ return;
+ }
+#endif
+
+ Assert( info.m_bTextureIsLockable );
+
+#ifndef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+ RECORD_STRUCT( &srcRect, sizeof(srcRect) );
+ RECORD_INT( D3DLOCK_NOSYSLOCK );
+#endif
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - D3DLockRect", __FUNCTION__ );
+
+ // lock the region (could be the full surface or less)
+ if ( FAILED( pTextureLevel->LockRect( &lockedRect, &srcRect, D3DLOCK_NOSYSLOCK ) ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect\n" );
+ pTextureLevel->Release();
+ return;
+ }
+ }
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - ConvertImageFormat", __FUNCTION__ );
+
+ // garymcthack : need to make a recording command for this.
+ ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
+ unsigned char *pImage = (unsigned char *)lockedRect.pBits;
+ ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
+ pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedRect.Pitch );
+ }
+
+#ifndef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+#endif
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UnlockRect", __FUNCTION__ );
+
+ if ( FAILED( pTextureLevel->UnlockRect() ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't unlock texture rect\n" );
+ pTextureLevel->Release();
+ return;
+ }
+ }
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - pTextureLevel->Release", __FUNCTION__ );
+ pTextureLevel->Release();
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Puts 2D texture data into 360 gpu memory.
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+static void BlitSurfaceBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ // xbox textures are NOT backed in gpu memory contiguously
+ // stride details are critical - see [Xbox 360 Texture Storage]
+ // a d3dformat identifier on the xbox is tiled, the same d3dformat on the pc is expected linear to the app
+ // we purposely hide the tiling here, otherwise much confusion for the pc
+ // the *entire* target must be un-tiled *only* before any *subrect* blitting linear work
+ // the *entire* target must then be re-tiled after the *subrect* blit
+ // procedural textures require this to subrect blit their new portions correctly
+ // the tiling dance can be avoided if the source and target match in tiled state during a full rect blit
+
+ if ( info.m_bSrcIsTiled )
+ {
+ // not supporting subrect blitting from a tiled source
+ Assert( 0 );
+ return;
+ }
+
+ CUtlBuffer formatConvertMemory;
+ unsigned char *pSrcData = info.m_pSrcData;
+
+ ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
+ if ( dstFormat != info.m_SrcFormat )
+ {
+ if ( !info.m_bCanConvertFormat )
+ {
+ // texture is expected to be in target format
+ // not supporting conversion of a tiled source
+ Assert( 0 );
+ return;
+ }
+
+ int srcSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, info.m_SrcFormat, false );
+ int dstSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, dstFormat, false );
+ formatConvertMemory.EnsureCapacity( dstSize );
+
+ // due to format conversion, source is in non-native order
+ ImageLoader::PreConvertSwapImageData( (unsigned char*)info.m_pSrcData, srcSize, info.m_SrcFormat, info.m_nWidth, srcStride );
+
+ // slow conversion operation
+ if ( !ShaderUtil()->ConvertImageFormat(
+ info.m_pSrcData,
+ info.m_SrcFormat,
+ (unsigned char*)formatConvertMemory.Base(),
+ dstFormat,
+ info.m_nWidth,
+ info.m_nHeight,
+ srcStride,
+ 0 ) )
+ {
+ // conversion failed
+ Assert( 0 );
+ return;
+ }
+
+ // due to format conversion, source must have been in non-native order
+ ImageLoader::PostConvertSwapImageData( (unsigned char*)formatConvertMemory.Base(), dstSize, dstFormat );
+
+ pSrcData = (unsigned char*)formatConvertMemory.Base();
+ }
+
+ // get the top mip level info (needed for proper sub mip access)
+ XGTEXTURE_DESC baseDesc;
+ XGGetTextureDesc( info.m_pTexture, 0, &baseDesc );
+ bool bDstIsTiled = XGIsTiledFormat( baseDesc.Format ) == TRUE;
+
+ // get the target mip level info
+ XGTEXTURE_DESC mipDesc;
+ XGGetTextureDesc( info.m_pTexture, info.m_nLevel, &mipDesc );
+ bool bFullSurfBlit = ( mipDesc.Width == (unsigned)info.m_nWidth && mipDesc.Height == (unsigned)info.m_nHeight );
+
+ // get the mip level of the texture we want to write into
+ IDirect3DSurface* pTextureLevel;
+ HRESULT hr = GetSurfaceFromTexture( info.m_pTexture, info.m_nLevel, info.m_CubeFaceID, &pTextureLevel );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: GetSurfaceFromTexture() failure\n" );
+ return;
+ }
+
+ CUtlBuffer scratchMemory;
+ D3DLOCKED_RECT lockedRect;
+
+ hr = pTextureLevel->LockRect( &lockedRect, NULL, D3DLOCK_NOSYSLOCK );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect\n" );
+ goto cleanUp;
+ }
+ unsigned char *pTargetImage = (unsigned char *)lockedRect.pBits;
+
+ POINT p;
+ p.x = xOffset;
+ p.y = yOffset;
+
+ RECT r;
+ r.left = 0;
+ r.top = 0;
+ r.right = info.m_nWidth;
+ r.bottom = info.m_nHeight;
+
+ int blockSize = mipDesc.Width/mipDesc.WidthInBlocks;
+ if ( !srcStride )
+ {
+ srcStride = (mipDesc.Width/blockSize)*mipDesc.BytesPerBlock;
+ }
+
+ // subrect blitting path
+ if ( !bDstIsTiled )
+ {
+ // Copy the subrect without conversion
+ hr = XGCopySurface(
+ pTargetImage,
+ mipDesc.RowPitch,
+ mipDesc.Width,
+ mipDesc.Height,
+ mipDesc.Format,
+ &p,
+ pSrcData,
+ srcStride,
+ mipDesc.Format,
+ &r,
+ 0,
+ 0 );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: failed subrect copy\n" );
+ goto cleanUp;
+ }
+ }
+ else
+ {
+ int tileFlags = 0;
+ if ( !( mipDesc.Flags & XGTDESC_PACKED ) )
+ tileFlags |= XGTILE_NONPACKED;
+ if ( mipDesc.Flags & XGTDESC_BORDERED )
+ tileFlags |= XGTILE_BORDER;
+
+ // tile the temp store back into the target surface
+ XGTileTextureLevel(
+ baseDesc.Width,
+ baseDesc.Height,
+ info.m_nLevel,
+ XGGetGpuFormat( baseDesc.Format ),
+ tileFlags,
+ pTargetImage,
+ &p,
+ pSrcData,
+ srcStride,
+ &r );
+ }
+
+ hr = pTextureLevel->UnlockRect();
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't unlock texture rect\n" );
+ goto cleanUp;
+ }
+
+cleanUp:
+ pTextureLevel->Release();
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Blit in bits
+//-----------------------------------------------------------------------------
+#if !defined( _X360 )
+static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ D3DBOX srcBox;
+ D3DLOCKED_BOX lockedBox;
+ srcBox.Left = xOffset;
+ srcBox.Right = xOffset + info.m_nWidth;
+ srcBox.Top = yOffset;
+ srcBox.Bottom = yOffset + info.m_nHeight;
+ srcBox.Front = info.m_nZOffset;
+ srcBox.Back = info.m_nZOffset + 1;
+
+#ifndef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+ RECORD_STRUCT( &srcRect, sizeof(srcRect) );
+ RECORD_INT( D3DLOCK_NOSYSLOCK );
+#endif
+
+ IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
+ if ( FAILED( pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, &srcBox, D3DLOCK_NOSYSLOCK ) ) )
+ {
+ Warning( "BlitVolumeBits: couldn't lock volume texture rect\n" );
+ return;
+ }
+
+ // garymcthack : need to make a recording command for this.
+ ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
+ unsigned char *pImage = (unsigned char *)lockedBox.pBits;
+ ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
+ pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedBox.RowPitch );
+
+#ifndef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+#endif
+
+ if ( FAILED( pVolumeTexture->UnlockBox( info.m_nLevel ) ) )
+ {
+ Warning( "BlitVolumeBits: couldn't unlock volume texture rect\n" );
+ return;
+ }
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Puts 3D texture data into 360 gpu memory.
+// Does not support any subvolume or slice blitting.
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ if ( xOffset || yOffset || info.m_nZOffset || srcStride )
+ {
+ // not supporting any subvolume blitting
+ // the entire volume per mip must be blitted
+ Assert( 0 );
+ return;
+ }
+
+ ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
+ if ( dstFormat != info.m_SrcFormat )
+ {
+ // texture is expected to be in target format
+ // not supporting conversion
+ Assert( 0 );
+ return;
+ }
+
+ // get the top mip level info (needed for proper sub mip access)
+ XGTEXTURE_DESC baseDesc;
+ XGGetTextureDesc( info.m_pTexture, 0, &baseDesc );
+ bool bDstIsTiled = XGIsTiledFormat( baseDesc.Format ) == TRUE;
+ if ( info.m_bSrcIsTiled && !bDstIsTiled )
+ {
+ // not supporting a tiled source into an untiled target
+ Assert( 0 );
+ return;
+ }
+
+ // get the mip level info
+ XGTEXTURE_DESC mipDesc;
+ XGGetTextureDesc( info.m_pTexture, info.m_nLevel, &mipDesc );
+ bool bFullSurfBlit = ( mipDesc.Width == (unsigned int)info.m_nWidth && mipDesc.Height == (unsigned int)info.m_nHeight );
+
+ if ( !bFullSurfBlit )
+ {
+ // not supporting subrect blitting
+ Assert( 0 );
+ return;
+ }
+
+ D3DLOCKED_BOX lockedBox;
+
+ // get the mip level of the volume we want to write into
+ IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
+ HRESULT hr = pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, NULL, D3DLOCK_NOSYSLOCK );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitVolumeBits: Couldn't lock volume box\n" );
+ return;
+ }
+
+ unsigned char *pSrcData = info.m_pSrcData;
+ unsigned char *pTargetImage = (unsigned char *)lockedBox.pBits;
+
+ int tileFlags = 0;
+ if ( !( mipDesc.Flags & XGTDESC_PACKED ) )
+ tileFlags |= XGTILE_NONPACKED;
+ if ( mipDesc.Flags & XGTDESC_BORDERED )
+ tileFlags |= XGTILE_BORDER;
+
+ if ( !info.m_bSrcIsTiled && bDstIsTiled )
+ {
+ // tile the source directly into the target surface
+ XGTileVolumeTextureLevel(
+ baseDesc.Width,
+ baseDesc.Height,
+ baseDesc.Depth,
+ info.m_nLevel,
+ XGGetGpuFormat( baseDesc.Format ),
+ tileFlags,
+ pTargetImage,
+ NULL,
+ pSrcData,
+ mipDesc.RowPitch,
+ mipDesc.SlicePitch,
+ NULL );
+ }
+ else if ( !info.m_bSrcIsTiled && !bDstIsTiled )
+ {
+ // not implemented yet
+ Assert( 0 );
+ }
+ else
+ {
+ // not implemented yet
+ Assert( 0 );
+ }
+
+ hr = pVolumeTexture->UnlockBox( info.m_nLevel );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitVolumeBits: couldn't unlock volume box\n" );
+ return;
+ }
+}
+#endif
+
+// 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.
+// 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.
+// 6) LockRects should be used for copying between SYSTEMMEM and
+// MANAGED. For such a small copy, you'd avoid a significant
+// amount of overhead from the old CopyRects code. Ideally, you
+// should just lock the bottom of MANAGED and generate your
+// sub-4x4 data there.
+
+// NOTE: IF YOU CHANGE THIS, CHANGE THE VERSION IN PLAYBACK.CPP!!!!
+static void BlitTextureBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+#ifdef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_BLIT_TEXTURE_BITS, 14 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+ RECORD_INT( xOffset );
+ RECORD_INT( yOffset );
+ RECORD_INT( info.m_nZOffset );
+ RECORD_INT( info.m_nWidth );
+ RECORD_INT( info.m_nHeight );
+ RECORD_INT( info.m_SrcFormat );
+ RECORD_INT( srcStride );
+ RECORD_INT( GetImageFormat( info.m_pTexture ) );
+ // strides are in bytes.
+ int srcDataSize;
+ if ( srcStride == 0 )
+ {
+ srcDataSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, info.m_SrcFormat, false );
+ }
+ else
+ {
+ srcDataSize = srcStride * info.m_nHeight;
+ }
+ RECORD_INT( srcDataSize );
+ RECORD_STRUCT( info.m_pSrcData, srcDataSize );
+#endif // RECORD_TEXTURES
+
+ if ( !IsVolumeTexture( info.m_pTexture ) )
+ {
+ Assert( info.m_nZOffset == 0 );
+ BlitSurfaceBits( info, xOffset, yOffset, srcStride );
+ }
+ else
+ {
+ BlitVolumeBits( info, xOffset, yOffset, srcStride );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Texture image upload
+//-----------------------------------------------------------------------------
+void LoadTexture( TextureLoadInfo_t &info )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ Assert( info.m_pSrcData );
+ Assert( info.m_pTexture );
+
+#ifdef _DEBUG
+ ImageFormat format = GetImageFormat( info.m_pTexture );
+ Assert( (format != -1) && (format == FindNearestSupportedFormat( format, false, false, false )) );
+#endif
+
+ // Copy in the bits...
+ BlitTextureBits( info, 0, 0, 0 );
+}
+
+void LoadVolumeTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
+{
+ if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_VOLUMETEXTURE )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DVolumeTexture9 *pVolTex = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
+
+ D3DVOLUME_DESC desc;
+ if ( pVolTex->GetLevelDesc( 0, &desc ) != S_OK )
+ {
+ Warning( "LoadVolumeTextureFromVTF: couldn't get texture level description\n" );
+ return;
+ }
+
+ int iMipCount = pVolTex->GetLevelCount();
+ if ( pVTF->Depth() != (int)desc.Depth || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->MipCount() < iMipCount )
+ {
+ Warning( "LoadVolumeTextureFromVTF: VTF dimensions do not match texture\n" );
+ return;
+ }
+
+ TextureLoadInfo_t sliceInfo = info;
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ IDirect3DVolumeTexture9 *pStagingTexture = NULL;
+ if ( !info.m_bTextureIsLockable )
+ {
+ IDirect3DVolumeTexture9 *pTemp;
+ if ( Dx9Device()->CreateVolumeTexture( desc.Width, desc.Height, desc.Depth, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
+ {
+ Warning( "LoadVolumeTextureFromVTF: failed to create temporary staging texture\n" );
+ return;
+ }
+ sliceInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
+ sliceInfo.m_bTextureIsLockable = true;
+ pStagingTexture = pTemp;
+ }
+#endif
+
+ for ( int iMip = 0; iMip < iMipCount; ++iMip )
+ {
+ int w, h, d;
+ pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
+ sliceInfo.m_nLevel = iMip;
+ sliceInfo.m_nWidth = w;
+ sliceInfo.m_nHeight = h;
+ for ( int iSlice = 0; iSlice < d; ++iSlice )
+ {
+ sliceInfo.m_nZOffset = iSlice;
+ sliceInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, 0, iMip, 0, 0, iSlice );
+ BlitTextureBits( sliceInfo, 0, 0, 0 );
+ }
+ }
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ if ( pStagingTexture )
+ {
+ if ( Dx9Device()->UpdateTexture( pStagingTexture, pVolTex ) != S_OK )
+ {
+ Warning( "LoadVolumeTextureFromVTF: volume UpdateTexture failed\n" );
+ }
+ pStagingTexture->Release();
+ }
+#endif
+}
+
+void LoadCubeTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
+{
+ if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_CUBETEXTURE )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DCubeTexture9 *pCubeTex = static_cast<IDirect3DCubeTexture9*>( info.m_pTexture );
+
+ D3DSURFACE_DESC desc;
+ if ( pCubeTex->GetLevelDesc( 0, &desc ) != S_OK )
+ {
+ Warning( "LoadCubeTextureFromVTF: couldn't get texture level description\n" );
+ return;
+ }
+
+ int iMipCount = pCubeTex->GetLevelCount();
+ if ( pVTF->Depth() != 1 || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->FaceCount() < 6 || pVTF->MipCount() < iMipCount )
+ {
+ Warning( "LoadCubeTextureFromVTF: VTF dimensions do not match texture\n" );
+ return;
+ }
+
+ TextureLoadInfo_t faceInfo = info;
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ IDirect3DCubeTexture9 *pStagingTexture = NULL;
+ if ( !info.m_bTextureIsLockable )
+ {
+ IDirect3DCubeTexture9 *pTemp;
+ if ( Dx9Device()->CreateCubeTexture( desc.Width, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
+ {
+ Warning( "LoadCubeTextureFromVTF: failed to create temporary staging texture\n" );
+ return;
+ }
+ faceInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
+ faceInfo.m_bTextureIsLockable = true;
+ pStagingTexture = pTemp;
+ }
+#endif
+
+ for ( int iMip = 0; iMip < iMipCount; ++iMip )
+ {
+ int w, h, d;
+ pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
+ faceInfo.m_nLevel = iMip;
+ faceInfo.m_nWidth = w;
+ faceInfo.m_nHeight = h;
+ for ( int iFace = 0; iFace < 6; ++iFace )
+ {
+ faceInfo.m_CubeFaceID = (D3DCUBEMAP_FACES) iFace;
+ faceInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, iFace, iMip );
+ BlitTextureBits( faceInfo, 0, 0, 0 );
+ }
+ }
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ if ( pStagingTexture )
+ {
+ if ( Dx9Device()->UpdateTexture( pStagingTexture, pCubeTex ) != S_OK )
+ {
+ Warning( "LoadCubeTextureFromVTF: cube UpdateTexture failed\n" );
+ }
+ pStagingTexture->Release();
+ }
+#endif
+}
+
+void LoadTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
+{
+ TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 );
+
+ if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_TEXTURE )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DTexture9 *pTex = static_cast<IDirect3DTexture9*>( info.m_pTexture );
+
+ D3DSURFACE_DESC desc;
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - GetLevelDesc", __FUNCTION__ );
+ if ( pTex->GetLevelDesc( 0, &desc ) != S_OK )
+ {
+ Warning( "LoadTextureFromVTF: couldn't get texture level description\n" );
+ return;
+ }
+ }
+
+ int iMipCount = pTex->GetLevelCount();
+ if ( pVTF->Depth() != 1 || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->MipCount() < iMipCount || pVTF->FaceCount() <= (int)info.m_CubeFaceID )
+ {
+ Warning( "LoadTextureFromVTF: VTF dimensions do not match texture\n" );
+ return;
+ }
+
+ // Info may have a cube face ID if we are falling back to 2D sphere map support
+ TextureLoadInfo_t mipInfo = info;
+ int iVTFFaceNum = info.m_CubeFaceID;
+ mipInfo.m_CubeFaceID = (D3DCUBEMAP_FACES)0;
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ // If blitting more than one mip level of an unlockable texture, create a temporary
+ // texture for all mip levels only call UpdateTexture once. For textures with
+ // only a single mip level, fall back on the support in BlitSurfaceBits. -henryg
+ IDirect3DTexture9 *pStagingTexture = NULL;
+ if ( !info.m_bTextureIsLockable && iMipCount > 1 )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - CreateSysmemTexture", __FUNCTION__ );
+
+ IDirect3DTexture9 *pTemp;
+ if ( Dx9Device()->CreateTexture( desc.Width, desc.Height, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
+ {
+ Warning( "LoadTextureFromVTF: failed to create temporary staging texture\n" );
+ return;
+ }
+
+ mipInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
+ mipInfo.m_bTextureIsLockable = true;
+ pStagingTexture = pTemp;
+ }
+#endif
+
+ // Get the clamped resolutions from the VTF, then apply any clamping we've done from the higher level code.
+ // (For example, we chop off the bottom of the mipmap pyramid at 32x32--that is reflected in iMipCount, so
+ // honor that here).
+ int finest = 0, coarsest = 0;
+ pVTF->GetMipmapRange( &finest, &coarsest );
+ finest = Min( finest, iMipCount - 1 );
+ coarsest = Min( coarsest, iMipCount - 1 );
+ Assert( finest <= coarsest && coarsest < iMipCount );
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - BlitTextureBits", __FUNCTION__ );
+ for ( int iMip = finest; iMip <= coarsest; ++iMip )
+ {
+ int w, h, d;
+ pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
+ mipInfo.m_nLevel = iMip;
+ mipInfo.m_nWidth = w;
+ mipInfo.m_nHeight = h;
+ mipInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, iVTFFaceNum, iMip );
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - BlitTextureBits - %d", __FUNCTION__, iMip );
+
+ BlitTextureBits( mipInfo, 0, 0, 0 );
+ }
+ }
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ if ( pStagingTexture )
+ {
+ if ( ( coarsest - finest + 1 ) == iMipCount )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateTexture", __FUNCTION__ );
+ if ( Dx9Device()->UpdateTexture( pStagingTexture, pTex ) != S_OK )
+ {
+ Warning( "LoadTextureFromVTF: UpdateTexture failed\n" );
+ }
+ }
+ else
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface", __FUNCTION__ );
+
+ for ( int mip = finest; mip <= coarsest; ++mip )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface - %d", __FUNCTION__, mip );
+
+ IDirect3DSurface9 *pSrcSurf = NULL,
+ *pDstSurf = NULL;
+
+ if ( pStagingTexture->GetSurfaceLevel( mip, &pSrcSurf ) != S_OK )
+ Warning( "LoadTextureFromVTF: couldn't get surface level %d for system surface\n", mip );
+
+ if ( pTex->GetSurfaceLevel( mip, &pDstSurf ) != S_OK )
+ Warning( "LoadTextureFromVTF: couldn't get surface level %d for dest surface\n", mip );
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface - Call ", __FUNCTION__, mip );
+ if ( !pSrcSurf || !pDstSurf || Dx9Device()->UpdateSurface( pSrcSurf, NULL, pDstSurf, NULL ) != S_OK )
+ Warning( "LoadTextureFromVTF: surface update failed.\n" );
+ }
+
+ if ( pSrcSurf )
+ pSrcSurf->Release();
+
+ if ( pDstSurf )
+ pDstSurf->Release();
+ }
+ }
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - Cleanup", __FUNCTION__ );
+ pStagingTexture->Release();
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Upload to a sub-piece of a texture
+//-----------------------------------------------------------------------------
+void LoadSubTexture( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ Assert( info.m_pSrcData );
+ Assert( info.m_pTexture );
+
+#if defined( _X360 )
+ // xboxissue - not supporting subrect swizzling
+ Assert( !info.m_bSrcIsTiled );
+#endif
+
+#ifdef _DEBUG
+ ImageFormat format = GetImageFormat( info.m_pTexture );
+ Assert( (format == FindNearestSupportedFormat(format, false, false, false )) && (format != -1) );
+#endif
+
+ // Copy in the bits...
+ BlitTextureBits( info, xOffset, yOffset, srcStride );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the size of texture memory, in MB
+//-----------------------------------------------------------------------------
+// Helps with startup time.. we don't use the texture memory size for anything anyways
+#define DONT_CHECK_MEM
+
+int ComputeTextureMemorySize( const GUID &nDeviceGUID, D3DDEVTYPE deviceType )
+{
+#if defined( _X360 )
+ return 0;
+#elif defined( DONT_CHECK_MEM )
+ return (deviceType == D3DDEVTYPE_REF) ? (64 * 1024 * 1024) : 102236160;
+#else
+
+ FileHandle_t file = g_pFullFileSystem->Open( "vidcfg.bin", "rb", "EXECUTABLE_PATH" );
+ if ( file )
+ {
+ GUID deviceId;
+ int texSize;
+ g_pFullFileSystem->Read( &deviceId, sizeof(deviceId), file );
+ g_pFullFileSystem->Read( &texSize, sizeof(texSize), file );
+ g_pFullFileSystem->Close( file );
+ if ( nDeviceGUID == deviceId )
+ {
+ return texSize;
+ }
+ }
+ // How much texture memory?
+ if (deviceType == D3DDEVTYPE_REF)
+ return 64 * 1024 * 1024;
+
+ // Sadly, the only way to compute texture memory size
+ // is to allocate a crapload of textures until we can't any more
+ ImageFormat fmt = FindNearestSupportedFormat( IMAGE_FORMAT_BGR565, false, false, false );
+ int textureSize = ShaderUtil()->GetMemRequired( 256, 256, 1, fmt, false );
+
+ int totalSize = 0;
+ CUtlVector< IDirect3DBaseTexture* > textures;
+
+ s_bTestingVideoMemorySize = true;
+ while (true)
+ {
+ RECORD_COMMAND( DX8_CREATE_TEXTURE, 7 );
+ RECORD_INT( textures.Count() );
+ RECORD_INT( 256 );
+ RECORD_INT( 256 );
+ RECORD_INT( ImageLoader::ImageFormatToD3DFormat(fmt) );
+ RECORD_INT( 1 );
+ RECORD_INT( false );
+ RECORD_INT( 1 );
+
+ IDirect3DBaseTexture* pTex = CreateD3DTexture( 256, 256, 1, fmt, 1, 0 );
+ if (!pTex)
+ break;
+ totalSize += textureSize;
+
+ textures.AddToTail( pTex );
+ }
+ s_bTestingVideoMemorySize = false;
+
+ // Free all the temp textures
+ for (int i = textures.Size(); --i >= 0; )
+ {
+ RECORD_COMMAND( DX8_DESTROY_TEXTURE, 1 );
+ RECORD_INT( i );
+
+ DestroyD3DTexture( textures[i] );
+ }
+
+ file = g_pFullFileSystem->Open( "vidcfg.bin", "wb", "EXECUTABLE_PATH" );
+ if ( file )
+ {
+ g_pFullFileSystem->Write( &nDeviceGUID, sizeof(GUID), file );
+ g_pFullFileSystem->Write( &totalSize, sizeof(totalSize), file );
+ g_pFullFileSystem->Close( file );
+ }
+
+ return totalSize;
+#endif
+}