Files
Totterynine 2773eae4d7 shaderapidx11
use -dxlevel 110 to use it
2021-09-22 18:56:56 +05:00

1126 lines
28 KiB
C++

// HUH???
#define RAD_TELEMETRY_DISABLED
#include "TextureDx11.h"
#include "shaderapi/ishaderapi.h"
#include "shaderdevicedx11.h"
#include "shaderapidx11_global.h"
#include "shaderapi/ishaderutil.h"
#include "filesystem.h"
#include "bitmap/tgawriter.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
// Returns a matching ShaderResourceView format for the depth texture's format.
FORCEINLINE DXGI_FORMAT GetDepthSRVFormat( DXGI_FORMAT depthResourceFormat )
{
switch ( depthResourceFormat )
{
case DXGI_FORMAT_R16_TYPELESS:
return DXGI_FORMAT_R16_UNORM;
case DXGI_FORMAT_R24G8_TYPELESS:
return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
case DXGI_FORMAT_R32_TYPELESS:
return DXGI_FORMAT_R32_FLOAT;
case DXGI_FORMAT_R32G8X24_TYPELESS:
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
default:
return DXGI_FORMAT_UNKNOWN;
}
}
// Returns a matching DepthStencilView format for the depth texture's format.
FORCEINLINE DXGI_FORMAT GetDepthStencilViewFormat( DXGI_FORMAT depthResourceFormat )
{
switch ( depthResourceFormat )
{
case DXGI_FORMAT_R16_TYPELESS:
return DXGI_FORMAT_D16_UNORM;
case DXGI_FORMAT_R24G8_TYPELESS:
return DXGI_FORMAT_D24_UNORM_S8_UINT;
case DXGI_FORMAT_R32_TYPELESS:
return DXGI_FORMAT_D32_FLOAT;
case DXGI_FORMAT_R32G8X24_TYPELESS:
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
default:
return DXGI_FORMAT_UNKNOWN;
}
}
// We will have to convert srcFormat into what this function
// returns for use in D3D11.
ImageFormat CTextureDx11::GetClosestSupportedImageFormatForD3D11( ImageFormat srcFormat )
{
switch ( srcFormat )
{
case IMAGE_FORMAT_BGR888:
return IMAGE_FORMAT_BGRA8888;
case IMAGE_FORMAT_RGB888:
return IMAGE_FORMAT_RGBA8888;
default:
return srcFormat;
}
}
DXGI_FORMAT GetD3DFormat( ImageFormat format )
{
switch ( format )
{
// These are not exact but have the same number
// of channels and bits-per-channel.
case IMAGE_FORMAT_I8:
return DXGI_FORMAT_R8_UNORM;
case IMAGE_FORMAT_IA88:
return DXGI_FORMAT_R8G8_UNORM;
case IMAGE_FORMAT_UV88:
return DXGI_FORMAT_R8G8_UNORM;
case IMAGE_FORMAT_UVWQ8888:
case IMAGE_FORMAT_UVLX8888:
return DXGI_FORMAT_R8G8B8A8_UNORM;
// Depth buffer formats
case IMAGE_FORMAT_NV_DST24:
return DXGI_FORMAT_R24G8_TYPELESS;
case IMAGE_FORMAT_NV_DST16:
return DXGI_FORMAT_R16_TYPELESS;
// These ones match D3D.
case IMAGE_FORMAT_A8:
return DXGI_FORMAT_A8_UNORM;
case IMAGE_FORMAT_DXT1:
case IMAGE_FORMAT_DXT1_ONEBITALPHA:
return DXGI_FORMAT_BC1_UNORM;
//case IMAGE_FORMAT_DXT1_SRGB:
//case IMAGE_FORMAT_DXT1_ONEBITALPHA_SRGB:
return DXGI_FORMAT_BC1_UNORM_SRGB;
case IMAGE_FORMAT_DXT3:
return DXGI_FORMAT_BC2_UNORM;
//case IMAGE_FORMAT_DXT3_SRGB:
return DXGI_FORMAT_BC2_UNORM_SRGB;
case IMAGE_FORMAT_DXT5:
return DXGI_FORMAT_BC3_UNORM;
//case IMAGE_FORMAT_DXT5_SRGB:
return DXGI_FORMAT_BC3_UNORM_SRGB;
case IMAGE_FORMAT_BGRA4444:
return DXGI_FORMAT_B4G4R4A4_UNORM;
case IMAGE_FORMAT_BGRX5551:
return DXGI_FORMAT_B5G5R5A1_UNORM;
case IMAGE_FORMAT_BGR565:
return DXGI_FORMAT_B5G6R5_UNORM;
case IMAGE_FORMAT_BGRX8888:
return DXGI_FORMAT_B8G8R8X8_UNORM;
//case IMAGE_FORMAT_BGRX8888_SRGB:
return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;
case IMAGE_FORMAT_ARGB8888: // unsupported?
return DXGI_FORMAT_R8G8B8A8_UNORM;
case IMAGE_FORMAT_BGRA8888:
return DXGI_FORMAT_B8G8R8A8_UNORM;
//case IMAGE_FORMAT_BGRA8888_SRGB:
return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
case IMAGE_FORMAT_RGBA16161616F:
return DXGI_FORMAT_R16G16B16A16_FLOAT;
case IMAGE_FORMAT_RGBA16161616:
return DXGI_FORMAT_R16G16B16A16_UNORM;
case IMAGE_FORMAT_R32F:
return DXGI_FORMAT_R32_FLOAT;
case IMAGE_FORMAT_RGBA32323232F:
return DXGI_FORMAT_R32G32B32A32_FLOAT;
case IMAGE_FORMAT_RGBA8888:
return DXGI_FORMAT_R8G8B8A8_UNORM;
//case IMAGE_FORMAT_RGBA8888_SRGB:
return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
default:
return DXGI_FORMAT_UNKNOWN;
}
}
ImageFormat CTextureDx11::GetImageFormat( DXGI_FORMAT d3dFormat )
{
switch ( d3dFormat )
{
case DXGI_FORMAT_UNKNOWN:
return IMAGE_FORMAT_UNKNOWN;
// These are not exact but have the same number
// of channels and bits-per-channel.
case DXGI_FORMAT_R8_UNORM:
return IMAGE_FORMAT_I8;
case DXGI_FORMAT_R8G8_UNORM:
return IMAGE_FORMAT_IA88;
case DXGI_FORMAT_R8G8B8A8_UNORM:
return IMAGE_FORMAT_RGBA8888;
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
return IMAGE_FORMAT_RGBA8888;// _SRGB;
case DXGI_FORMAT_A8_UNORM:
return IMAGE_FORMAT_A8;
case DXGI_FORMAT_BC1_UNORM:
return IMAGE_FORMAT_DXT1;
case DXGI_FORMAT_BC1_UNORM_SRGB:
return IMAGE_FORMAT_DXT1;// _SRGB;
case DXGI_FORMAT_BC2_UNORM:
return IMAGE_FORMAT_DXT3;
case DXGI_FORMAT_BC2_UNORM_SRGB:
return IMAGE_FORMAT_DXT3;// _SRGB;
case DXGI_FORMAT_BC3_UNORM:
return IMAGE_FORMAT_DXT5;
case DXGI_FORMAT_BC3_UNORM_SRGB:
return IMAGE_FORMAT_DXT5;// _SRGB;
case DXGI_FORMAT_B4G4R4A4_UNORM:
return IMAGE_FORMAT_BGRA4444;
case DXGI_FORMAT_B5G6R5_UNORM:
return IMAGE_FORMAT_BGR565;
case DXGI_FORMAT_B8G8R8X8_UNORM:
return IMAGE_FORMAT_BGRX8888;
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
return IMAGE_FORMAT_BGRX8888;// _SRGB;
case DXGI_FORMAT_B8G8R8A8_UNORM:
return IMAGE_FORMAT_BGRA8888;
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
return IMAGE_FORMAT_BGRA8888;// _SRGB;
case DXGI_FORMAT_R16G16B16A16_FLOAT:
return IMAGE_FORMAT_RGBA16161616F;
case DXGI_FORMAT_R16G16B16A16_UNORM:
return IMAGE_FORMAT_RGBA16161616;
case DXGI_FORMAT_R32_FLOAT:
return IMAGE_FORMAT_R32F;
case DXGI_FORMAT_R32G32B32A32_FLOAT:
return IMAGE_FORMAT_RGBA32323232F;
default:
return IMAGE_FORMAT_UNKNOWN;
}
}
int CTextureDx11::CalcRamBytes() const
{
int rWidth = m_nWidth;
int rHeight = m_nHeight;
int rDepth = m_Depth;
int nRamBytes = 0;
for ( int i = 0; i < m_NumLevels; i++ )
{
nRamBytes += ImageLoader::GetMemRequired( rWidth, rHeight, rDepth, m_Format, false );
if ( rWidth == 1 && rHeight == 1 && rDepth == 1 )
{
break;
}
rDepth >>= 1;
rWidth >>= 1;
rHeight >>= 1;
if ( rWidth < 1 )
{
rWidth = 1;
}
if ( rHeight < 1 )
{
rHeight = 1;
}
if ( rDepth < 1 )
{
rDepth = 1;
}
}
return nRamBytes;
}
// Texture2D is used for regular 2D textures, cubemaps, and 2D texture arrays
// TODO: Support 1D and 3D textures?
ID3D11Resource *CTextureDx11::CreateD3DTexture( int width, int height, int nDepth,
ImageFormat dstFormat, int numLevels, int nCreationFlags )
{
if ( nDepth <= 0 )
nDepth = 1;
bool isCubeMap = ( nCreationFlags & TEXTURE_CREATE_CUBEMAP ) != 0;
if ( isCubeMap )
nDepth = 6;
bool bIsRenderTarget = ( nCreationFlags & TEXTURE_CREATE_RENDERTARGET ) != 0;
//bool bManaged = ( nCreationFlags & TEXTURE_CREATE_MANAGED ) != 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;
// NOTE: This function shouldn't be used for creating depth buffers!
//Assert( !bIsDepthBuffer );
dstFormat = GetClosestSupportedImageFormatForD3D11( dstFormat );
m_Format = dstFormat;
DXGI_FORMAT d3dFormat = DXGI_FORMAT_UNKNOWN;
d3dFormat = GetD3DFormat( dstFormat );
if ( d3dFormat == DXGI_FORMAT_UNKNOWN )
{
Warning( "ShaderAPIDX11::CreateD3DTexture: Invalid image format %i!\n", (int)dstFormat );
Assert( 0 );
return 0;
}
m_D3DFormat = d3dFormat;
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
if ( isDynamic )
{
usage = D3D11_USAGE_DYNAMIC;
}
UINT miscFlags = 0;
if ( bAutoMipMap )
{
miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS;
}
if ( isCubeMap )
{
miscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
}
UINT bindFlags = D3D11_BIND_SHADER_RESOURCE;
if ( bIsRenderTarget )
{
bindFlags |= D3D11_BIND_RENDER_TARGET;
}
if ( bIsDepthBuffer )
{
bindFlags |= D3D11_BIND_DEPTH_STENCIL;
}
UINT cpuAccessFlags = 0;
if ( isDynamic )
{
cpuAccessFlags = D3D11_CPU_ACCESS_WRITE;
}
ID3D11Resource *pBaseTexture = NULL;
HRESULT hr = S_OK;
// TODO: Support 1D and 3D textures
// (2D textures are good for regular textures, cubemaps, and texture arrays)
D3D11_TEXTURE2D_DESC desc;
ZeroMemory( &desc, sizeof( D3D11_TEXTURE2D_DESC ) );
desc.ArraySize = nDepth;
desc.Format = d3dFormat;
desc.Width = width;
desc.Height = height;
desc.MipLevels = numLevels;
desc.MiscFlags = miscFlags;
desc.BindFlags = bindFlags;
desc.CPUAccessFlags = cpuAccessFlags;
desc.Usage = usage;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
ID3D11Texture2D *pTex2D = NULL;
hr = D3D11Device()->CreateTexture2D( &desc, NULL, &pTex2D );
pBaseTexture = pTex2D;
if ( FAILED( hr ) )
{
switch ( hr )
{
case E_OUTOFMEMORY:
Warning( "TextureDx11::CreateD3DTexture: E_OUTOFMEMORY\n" );
break;
default:
break;
}
return 0;
}
//s_TextureCount++;
return pBaseTexture;
}
void DestroyD3DTexture( ID3D11Resource *pD3DTex )
{
if ( pD3DTex )
{
pD3DTex->Release();
Assert( ref == 0 );
//s_TextureCount--;
}
}
//-----------------------------------
// Dx11 implementation of a texture
//-----------------------------------
CTextureDx11::CTextureDx11()
{
m_pLockedFace = NULL;
m_nLockedFaceSize = 0;
m_pLockedTexture = NULL;
m_LockedSubresource = 0;
m_bLocked = false;
m_nFlags = 0;
m_Count = 0;
m_CountIndex = 0;
m_nTimesBoundMax = 0;
m_nTimesBoundThisFrame = 0;
m_Anisotropy = 0;
m_Format = IMAGE_FORMAT_RGBA8888;
m_MinFilter = D3D11_FILTER_TYPE_LINEAR;
m_MagFilter = D3D11_FILTER_TYPE_LINEAR;
m_MipFilter = D3D11_FILTER_TYPE_POINT;
m_bIsAnisotropic = false;
m_UTexWrap = D3D11_TEXTURE_ADDRESS_CLAMP;
m_VTexWrap = D3D11_TEXTURE_ADDRESS_CLAMP;
m_WTexWrap = D3D11_TEXTURE_ADDRESS_CLAMP;
m_Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
m_pTexture = NULL;
m_ppTexture = NULL;
m_pSamplerState = NULL;
m_pView = NULL;
m_ppView = NULL;
m_pDepthStencilView = NULL;
m_pRenderTargetView = NULL;
m_pRamImage = NULL;
m_ppRamImage = NULL;
}
inline int CalcMipLevels( int w, int h )
{
return /*ceil( log2( max( w, h ) ) ) +*/ 1; // we dont support mips yet
}
void CTextureDx11::SetupTexture2D( int width, int height, int depth, int count, int i,
int flags, int numCopies, int numMipLevels, ImageFormat dstImageFormat )
{
if ( dstImageFormat == IMAGE_FORMAT_I8 )
{
//DebuggerBreak();
}
//Log( "Making texture2D\n" );
bool bIsRenderTarget = ( flags & TEXTURE_CREATE_RENDERTARGET ) != 0;
bool bIsDepthBuffer = ( flags & TEXTURE_CREATE_DEPTHBUFFER ) != 0;
if ( bIsDepthBuffer )
{
//Log( "Making depth buffer\n" );
SetupDepthTexture( dstImageFormat, width, height, "depth", true );
return;
}
else if ( bIsRenderTarget )
{
//Log( "Making render target\n" );
SetupBackBuffer( width, height, "rendertarget", NULL, dstImageFormat );
return;
}
//dstImageFormat = IMAGE_FORMAT_RGBA8888;
//---------------------------------------------------------------------------------
if ( depth == 0 )
depth = 1;
bool bIsCubeMap = ( flags & TEXTURE_CREATE_CUBEMAP ) != 0;
if ( bIsCubeMap )
depth = 6;
bool bIsDynamic = ( flags & TEXTURE_CREATE_DYNAMIC ) != 0;
//bool bAutoMipMap = ( flags & TEXTURE_CREATE_AUTOMIPMAP ) != 0;
bool bIsManaged = ( flags & TEXTURE_CREATE_MANAGED ) != 0;
// Can't be both managed + dynamic. Dynamic is an optimization, but
// if it's not managed, then we gotta do special client-specific stuff
// So, managed wins out!
if ( bIsManaged )
bIsDynamic = false;
/*if ( bAutoMipMap && numMipLevels == 0 && !bIsDynamic )
{
numMipLevels = CalcMipLevels( width, height );
}
else if ( bIsDynamic )*/
{
// Dynamic textures can't have mipmaps
numMipLevels = 1;
}
m_iTextureType = TEXTURE_STANDARD;
m_iTextureDimensions = TEXTURE_2D;
unsigned short usSetFlags = 0;
usSetFlags |= ( flags & TEXTURE_CREATE_VERTEXTEXTURE ) ? CTextureDx11::IS_VERTEX_TEXTURE : 0;
m_nFlags = CTextureDx11::IS_ALLOCATED;
m_nWidth = width;
m_nHeight = height;
m_Depth = depth;
m_Count = count;
m_CountIndex = i;
m_CreationFlags = flags;
m_nFlags |= usSetFlags;
m_NumLevels = numMipLevels;
ID3D11Resource *pD3DTex;
// Set the initial texture state
if ( numCopies <= 1 )
{
m_NumCopies = 1;
pD3DTex = CreateD3DTexture( width, height, depth, dstImageFormat, numMipLevels, flags );
SetTexture( pD3DTex );
if ( bIsDynamic )
{
int nRamBytes = CalcRamBytes();
m_pRamImage = new unsigned char[nRamBytes];
memset( m_pRamImage, 0, nRamBytes );
}
}
else
{
m_NumCopies = numCopies;
m_ppTexture = new ID3D11Resource * [numCopies];
if ( bIsDynamic )
m_ppRamImage = new unsigned char * [numCopies];
for ( int k = 0; k < numCopies; k++ )
{
pD3DTex = CreateD3DTexture( width, height, depth, dstImageFormat, numMipLevels, flags );
SetTexture( k, pD3DTex );
if ( bIsDynamic )
{
int nRamBytes = CalcRamBytes();
m_ppRamImage[k] = new unsigned char[nRamBytes];
memset( m_ppRamImage[k], 0, nRamBytes );
}
}
}
m_CurrentCopy = 0;
if ( m_NumCopies == 1 )
pD3DTex = m_pTexture;
else
pD3DTex = m_ppTexture[m_CurrentCopy];
m_UTexWrap = D3D11_TEXTURE_ADDRESS_CLAMP;
m_VTexWrap = D3D11_TEXTURE_ADDRESS_CLAMP;
m_WTexWrap = D3D11_TEXTURE_ADDRESS_CLAMP;
m_MipFilter = ( numMipLevels != 1 ) ?
D3D11_FILTER_TYPE_LINEAR : D3D11_FILTER_TYPE_POINT;
m_MinFilter = m_MagFilter = D3D11_FILTER_TYPE_LINEAR;
m_SwitchNeeded = false;
AdjustD3DFilter();
MakeView();
}
void CTextureDx11::SetupDepthTexture( ImageFormat depthFormat, int width, int height, const char *pDebugName, bool bTexture )
{
m_nFlags = CTextureDx11::IS_ALLOCATED;
if ( bTexture )
m_nFlags |= CTextureDx11::IS_DEPTH_STENCIL_TEXTURE;
else
m_nFlags |= CTextureDx11::IS_DEPTH_STENCIL;
m_iTextureType = TEXTURE_DEPTHSTENCIL;
m_iTextureDimensions = TEXTURE_3D;
m_nWidth = width;
m_nHeight = height;
m_Depth = 1;
m_Count = 1;
m_CountIndex = 0;
m_CreationFlags = TEXTURE_CREATE_DEPTHBUFFER;
m_MinFilter = D3D11_FILTER_TYPE_LINEAR;
m_MagFilter = D3D11_FILTER_TYPE_LINEAR;
m_MipFilter = D3D11_FILTER_TYPE_POINT;
m_NumLevels = 1;
m_NumCopies = 1;
m_CurrentCopy = 0;
m_pTexture = CreateD3DTexture(
width, height, m_Depth, depthFormat, m_NumLevels, m_CreationFlags );
AdjustD3DFilter();
MakeDepthStencilView();
if ( bTexture )
{
MakeView();
}
}
void CTextureDx11::SetupBackBuffer( int width, int height, const char *pDebugName,
ID3D11Texture2D *pBackBuffer, ImageFormat format )
{
m_nFlags = CTextureDx11::IS_ALLOCATED;
m_iTextureType = TEXTURE_RENDERTARGET;
m_iTextureDimensions = TEXTURE_2D;
m_nWidth = width;
m_nHeight = height;
m_Depth = 1;
m_Count = 1;
m_CountIndex = 0;
m_CreationFlags = TEXTURE_CREATE_RENDERTARGET;
m_MinFilter = D3D11_FILTER_TYPE_LINEAR;
m_MagFilter = D3D11_FILTER_TYPE_LINEAR;
m_MipFilter = D3D11_FILTER_TYPE_POINT;
m_NumLevels = 1;
m_NumCopies = 1;
m_CurrentCopy = 0;
m_Format = GetClosestSupportedImageFormatForD3D11( format );
m_D3DFormat = GetD3DFormat( m_Format );
if ( pBackBuffer )
m_pTexture = pBackBuffer;
else
m_pTexture = CreateD3DTexture( width, height, m_Depth, format, m_NumLevels, m_CreationFlags );
AdjustD3DFilter();
MakeRenderTargetView();
MakeView();
}
void CTextureDx11::SetMinFilter( ShaderTexFilterMode_t texFilterMode )
{
switch ( texFilterMode )
{
case SHADER_TEXFILTERMODE_LINEAR:
case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST:
m_MinFilter = D3D11_FILTER_TYPE_LINEAR;
m_MipFilter = D3D11_FILTER_TYPE_POINT;
m_bIsAnisotropic = false;
break;
case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR:
m_MinFilter = D3D11_FILTER_TYPE_LINEAR;
m_MipFilter = D3D11_FILTER_TYPE_LINEAR;
m_bIsAnisotropic = false;
break;
case SHADER_TEXFILTERMODE_NEAREST:
case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST:
m_MinFilter = D3D11_FILTER_TYPE_POINT;
m_MipFilter = D3D11_FILTER_TYPE_POINT;
m_bIsAnisotropic = false;
break;
case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR:
m_MinFilter = D3D11_FILTER_TYPE_POINT;
m_MipFilter = D3D11_FILTER_TYPE_LINEAR;
m_bIsAnisotropic = false;
break;
case SHADER_TEXFILTERMODE_ANISOTROPIC:
m_bIsAnisotropic = true;
break;
}
AdjustD3DFilter();
}
void CTextureDx11::SetMagFilter( ShaderTexFilterMode_t texFilterMode )
{
switch ( texFilterMode )
{
case SHADER_TEXFILTERMODE_LINEAR:
m_MagFilter = D3D11_FILTER_TYPE_LINEAR;
break;
case SHADER_TEXFILTERMODE_NEAREST:
m_MagFilter = D3D11_FILTER_TYPE_POINT;
break;
}
AdjustD3DFilter();
}
void CTextureDx11::SetWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode )
{
D3D11_TEXTURE_ADDRESS_MODE address;
switch ( wrapMode )
{
case SHADER_TEXWRAPMODE_CLAMP:
address = D3D11_TEXTURE_ADDRESS_CLAMP;
break;
case SHADER_TEXWRAPMODE_REPEAT:
address = D3D11_TEXTURE_ADDRESS_WRAP;
break;
case SHADER_TEXWRAPMODE_BORDER:
address = D3D11_TEXTURE_ADDRESS_BORDER;
break;
default:
address = D3D11_TEXTURE_ADDRESS_CLAMP;
Warning( "CTextureDx11::SetWrap: unknown wrapMode %i\n", wrapMode );
break;
}
switch ( coord )
{
case SHADER_TEXCOORD_S:
m_UTexWrap = address;
break;
case SHADER_TEXCOORD_T:
m_VTexWrap = address;
break;
case SHADER_TEXCOORD_U:
m_WTexWrap = address;
break;
default:
Warning( "CTextureDx11::SetWrap: unknown coord %i\n", coord );
break;
}
AdjustSamplerState();
}
void CTextureDx11::AdjustD3DFilter()
{
// Set to anisotropic if the texture was already set to an anisotropic filter,
// or we are using at least bilinear filtering and have an anisotropic level > 1
if ( m_bIsAnisotropic ||
( m_MinFilter == D3D11_FILTER_TYPE_LINEAR && m_MagFilter == D3D11_FILTER_TYPE_LINEAR && m_Anisotropy > 1 ) )
{
m_Filter = D3D11_FILTER_ANISOTROPIC;
}
else
{
m_Filter = D3D11_ENCODE_BASIC_FILTER( m_MinFilter, m_MagFilter, m_MipFilter,
D3D11_FILTER_REDUCTION_TYPE_STANDARD );
}
AdjustSamplerState();
}
void CTextureDx11::SetAnisotropicLevel( int level )
{
m_Anisotropy = level;
AdjustD3DFilter();
}
void CTextureDx11::AdjustSamplerState()
{
if ( m_pSamplerState )
m_pSamplerState->Release();
m_pSamplerState = NULL;
D3D11_SAMPLER_DESC desc;
ZeroMemory( &desc, sizeof( D3D11_SAMPLER_DESC ) );
desc.AddressU = m_UTexWrap;
desc.AddressV = m_VTexWrap;
desc.AddressW = m_WTexWrap;
desc.Filter = m_Filter;
desc.MaxAnisotropy = m_Anisotropy;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0;
desc.MaxLOD = D3D11_FLOAT32_MAX;
HRESULT hr = D3D11Device()->CreateSamplerState( &desc, &m_pSamplerState );
if ( FAILED( hr ) )
{
Warning( "CTextureDx11: Couldn't create sampler state!\n" );
}
}
void CTextureDx11::MakeRenderTargetView()
{
if ( m_iTextureType != TEXTURE_RENDERTARGET )
{
return;
}
D3D11_RENDER_TARGET_VIEW_DESC desc;
ZeroMemory( &desc, sizeof( D3D11_RENDER_TARGET_VIEW_DESC ) );
desc.Format = m_D3DFormat;
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
if ( m_pRenderTargetView )
{
m_pRenderTargetView->Release();
Assert( ref == 0 );
}
HRESULT hr = D3D11Device()->CreateRenderTargetView( m_pTexture, &desc, &m_pRenderTargetView );
if ( FAILED( hr ) )
{
Warning( "Failed to make D3D render target view!\n" );
}
}
void CTextureDx11::MakeDepthStencilView()
{
if ( m_iTextureType != TEXTURE_DEPTHSTENCIL )
{
return;
}
D3D11_DEPTH_STENCIL_VIEW_DESC desc;
ZeroMemory( &desc, sizeof( D3D11_DEPTH_STENCIL_VIEW_DESC ) );
desc.Format = GetDepthStencilViewFormat( m_D3DFormat );
desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
desc.Flags = 0;
if ( m_pDepthStencilView )
{
m_pDepthStencilView->Release();
Assert( ref == 0 );
}
HRESULT hr = D3D11Device()->CreateDepthStencilView( m_pTexture, &desc, &m_pDepthStencilView );
if ( FAILED( hr ) )
{
Warning( "Failed to make D3D depth stencil view!\n" );
}
}
void CTextureDx11::MakeView()
{
DXGI_FORMAT format;
if ( m_iTextureType == TEXTURE_DEPTHSTENCIL )
{
format = GetDepthSRVFormat( m_D3DFormat );
}
else
{
format = m_D3DFormat;
}
D3D11_SRV_DIMENSION dim;
if ( m_Depth == 6 && ( ( m_CreationFlags & TEXTURE_CREATE_CUBEMAP ) != 0 ) )
{
dim = D3D11_SRV_DIMENSION_TEXTURECUBE;
}
else if ( m_Depth > 1 )
{
dim = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
}
else
{
dim = D3D11_SRV_DIMENSION_TEXTURE2D;
}
CD3D11_SHADER_RESOURCE_VIEW_DESC desc( dim, format );
if ( m_NumCopies > 1 )
{
if ( m_ppView )
{
delete[] m_ppView;
}
m_ppView = new ID3D11ShaderResourceView * [m_NumCopies];
for ( int copy = 0; copy < m_NumCopies; copy++ )
{
HRESULT hr = D3D11Device()->CreateShaderResourceView( m_ppTexture[copy], &desc, &m_ppView[copy] );
if ( FAILED( hr ) )
{
Warning( "Unable to create shader resource view for texture copy %i!\n", copy );
}
}
}
else
{
if ( m_pView )
{
m_pView->Release();
}
m_pView = NULL;
HRESULT hr = D3D11Device()->CreateShaderResourceView( m_pTexture, &desc, &m_pView );
if ( FAILED( hr ) )
{
Warning( "Unable to create D3D11 Texture view!\n" );
}
}
}
static int s_CubemapBlits = 0;
void CTextureDx11::BlitSurfaceBits( CTextureDx11::TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
{
if ( m_CreationFlags & TEXTURE_CREATE_DYNAMIC )
{
// Dynamic textures need to be updated using Lock() and Unlock()
Warning( "TextureDX11: Tried to call BlitSurfaceBits() on a dynamic texture!\n" );
return;
}
int width = info.m_nWidth;
int height = info.m_nHeight;
if ( m_Format == IMAGE_FORMAT_DXT3 || //m_Format == IMAGE_FORMAT_DXT3_SRGB ||
m_Format == IMAGE_FORMAT_DXT5 || //m_Format == IMAGE_FORMAT_DXT5_SRGB ||
m_Format == IMAGE_FORMAT_DXT1 || //m_Format == IMAGE_FORMAT_DXT1_SRGB ||
m_Format == IMAGE_FORMAT_DXT1_ONEBITALPHA )//|| m_Format == IMAGE_FORMAT_DXT1_ONEBITALPHA_SRGB )
{
width = ALIGN_VALUE( width, 4 );
height = ALIGN_VALUE( height, 4 );
}
CD3D11_BOX box;
box.left = xOffset;
box.right = xOffset + width;
box.top = yOffset;
box.bottom = yOffset + height;
box.front = info.m_nZOffset;
box.back = info.m_nZOffset + 1;
int mem = ImageLoader::GetMemRequired( width, height, info.m_nZOffset, m_Format, false );
unsigned char *pNewImage = new unsigned char[mem];
int dstStride = ImageLoader::SizeInBytes( m_Format );
int pitch = dstStride * width;
if ( m_Format == IMAGE_FORMAT_DXT3 || //m_Format == IMAGE_FORMAT_DXT3_SRGB ||
m_Format == IMAGE_FORMAT_DXT5 )//|| m_Format == IMAGE_FORMAT_DXT5_SRGB )
{
pitch = 16 * ( width / 4 );
}
else if ( m_Format == IMAGE_FORMAT_DXT1 || //m_Format == IMAGE_FORMAT_DXT1_SRGB ||
m_Format == IMAGE_FORMAT_DXT1_ONEBITALPHA )//|| m_Format == IMAGE_FORMAT_DXT1_ONEBITALPHA_SRGB )
{
pitch = 8 * ( width / 4 );
}
bool ret =
ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat, pNewImage, m_Format,
width, height, srcStride );
if ( !ret )
{
Warning( "Couldn't convert texture for uploading to D3D!\n" );
return;
}
#if 0
if ( m_CreationFlags & TEXTURE_CREATE_CUBEMAP )
{
char cmfile[100];
sprintf( cmfile, "C:\\Users\\Brian\\Desktop\\SourceDX11Debug\\cubemap-%i-face-%i.tga", s_CubemapBlits, info.m_CubeFaceID );
TGAWriter::WriteTGAFile( cmfile, info.m_nWidth, info.m_nHeight, m_Format, pNewImage, dstStride * info.m_nWidth );
if ( info.m_CubeFaceID == 4 )
{
s_CubemapBlits++;
}
}
#endif
UINT subresource = D3D11CalcSubresource( info.m_nLevel, info.m_CubeFaceID, m_NumLevels );
D3D11DeviceContext()->UpdateSubresource( info.m_pTexture, subresource, &box, pNewImage,
pitch, 0 );
delete[] pNewImage;
// If the texture was created with auto mipmap and we have just filled in the base mip,
// make D3D generate the remaining mips. If the texture was not created with auto mipmap,
// or we have just filled in a non-base mip, we assume the user is filling in the mips.
if ( ( ( m_CreationFlags & TEXTURE_CREATE_AUTOMIPMAP ) != 0 ) && m_NumLevels > 1 && info.m_nLevel == 0 )
{
D3D11DeviceContext()->GenerateMips( info.m_pView );
}
}
void CTextureDx11::BlitTextureBits( CTextureDx11::TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
{
// TODO: Volume texture?
//Assert( info.m_nZOffset == 0 );
if ( info.m_nZOffset != 0 )
{
return;
}
BlitSurfaceBits( info, xOffset, yOffset, srcStride );
}
void CTextureDx11::LoadTexImage( CTextureDx11::TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
{
MEM_ALLOC_CREDIT();
Assert( info.m_pSrcData );
Assert( info.m_pTexture );
// Copy in the bits...
BlitTextureBits( info, xOffset, yOffset, srcStride );
}
void CTextureDx11::LoadTextureFromVTF(CTextureDx11::TextureLoadInfo_t& info, IVTFTexture* pVTF, int iVTFFrame)
{
BlitTextureBits(info, 0, 0, 0);
}
void CTextureDx11::Delete()
{
int nDeallocated = 0;
if ( m_NumCopies == 1 )
{
if ( m_pView )
{
m_pView->Release();
Assert( refCount == 0 );
m_pView = 0;
nDeallocated++;
}
if ( m_pTexture )
{
DestroyD3DTexture( m_pTexture );
m_pTexture = 0;
nDeallocated = 1;
}
if ( m_pRamImage )
{
delete[] m_pRamImage;
m_pRamImage = NULL;
}
}
else
{
if ( m_ppView )
{
for ( int i = 0; i < m_NumCopies; i++ )
{
if ( m_ppView[i] )
{
m_ppView[i]->Release();
Assert( refCount == 0 );
nDeallocated++;
}
}
delete[] m_ppView;
m_ppView = NULL;
}
if ( m_ppTexture )
{
// Multiple copy texture
for ( int j = 0; j < m_NumCopies; j++ )
{
if ( m_ppTexture[j] )
{
DestroyD3DTexture( m_ppTexture[j] );
m_ppTexture[j] = 0;
++nDeallocated;
}
}
delete[] m_ppTexture;
m_ppTexture = NULL;
}
if ( m_ppRamImage )
{
delete[] m_ppRamImage;
m_ppRamImage = NULL;
}
}
if ( m_iTextureType == TEXTURE_RENDERTARGET )
{
if ( m_pRenderTargetView )
{
m_pRenderTargetView->Release();
Assert( refCount == 0 );
m_pRenderTargetView = 0;
nDeallocated++;
}
}
else if ( m_iTextureType == TEXTURE_DEPTHSTENCIL )
{
if ( m_pDepthStencilView )
{
m_pDepthStencilView->Release();
Assert( refCount == 0 );
m_pDepthStencilView = 0;
nDeallocated++;
}
}
if ( m_pSamplerState )
{
m_pSamplerState->Release();
m_pSamplerState = 0;
nDeallocated++;
}
m_NumCopies = 0;
m_nFlags = 0;
}
bool CTextureDx11::Lock( int copy, int level, int cubeFaceID, int xOffset, int yOffset,
int width, int height, bool bDiscard, CPixelWriter &writer )
{
Assert( !m_bLocked );
Assert( level == 0 ); // dynamic textures can't have mipmaps
if ( m_bLocked )
{
return false;
}
if ( m_NumCopies == 1 )
{
m_pLockedTexture = m_pTexture;
m_pLockedFace = m_pRamImage;
}
else
{
m_pLockedTexture = m_ppTexture[copy];
m_pLockedFace = m_ppRamImage[copy];
}
int bytesPerXel = ImageLoader::SizeInBytes( m_Format );
int bytesPerRow = bytesPerXel * m_nWidth;
int bytesPerFace = bytesPerXel * m_nWidth * m_nHeight;
// Where do we want to start modifying?
int nMemOffset = bytesPerFace * cubeFaceID;
nMemOffset += yOffset * bytesPerRow;
nMemOffset += xOffset * bytesPerXel;
// Offset into the ram image
unsigned char *pModifyBegin = m_pLockedFace + nMemOffset;
m_nLockedFaceSize = bytesPerFace;
m_LockedSubresource = D3D11CalcSubresource( 0, cubeFaceID, 1 );
ZeroMemory( &m_MappedData, sizeof( D3D11_MAPPED_SUBRESOURCE ) );
HRESULT hr = D3D11DeviceContext()->Map( m_pLockedTexture, m_LockedSubresource, D3D11_MAP_WRITE_DISCARD, 0, &m_MappedData );
if ( FAILED( hr ) )
{
return false;
}
writer.SetPixelMemory( m_Format, pModifyBegin, bytesPerRow );
m_bLocked = true;
return true;
}
void CTextureDx11::Unlock( int copy, int level, int cubeFaceID )
{
Assert( m_bLocked );
if ( !m_bLocked )
{
return;
}
memcpy( m_MappedData.pData, m_pLockedFace, m_nLockedFaceSize );
D3D11DeviceContext()->Unmap( m_pLockedTexture, m_LockedSubresource );
m_pLockedFace = NULL;
m_nLockedFaceSize = 0;
m_pLockedTexture = NULL;
m_LockedSubresource = 0;
m_bLocked = false;
}