/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. // Description : Direct3D specific texture manager implementation. #include "StdAfx.h" #include "DriverD3D.h" #include "I3DEngine.h" #include "StringUtils.h" #include #include "BitFiddling.h" // ConvertBlock3DcToDXT5() #include "D3DStereo.h" #include "../Common/PostProcess/PostProcessUtils.h" #include "D3DPostProcess.h" #include "../Common/Textures/TextureHelpers.h" #include "../Common/Textures/TextureManager.h" #include "../Common/RenderCapabilities.h" #include #include #if AZ_RENDER_TO_TEXTURE_GEM_ENABLED #include #endif // AZ_RENDER_TO_TEXTURE_GEM_ENABLED #undef min #undef max //=============================================================================== namespace { void SetShaderResourceViewDesc(const SResourceView& rv, uint32 texType, D3DFormat format, int arraySize, uint32 nSliceCount, D3D11_SHADER_RESOURCE_VIEW_DESC& desc) { const uint nMipCount = rv.m_Desc.nMipCount == SResourceView().m_Desc.nMipCount ? (uint) - 1 : (uint)rv.m_Desc.nMipCount; ZeroStruct(desc); desc.Format = CTexture::ConvertToShaderResourceFmt(format); if (rv.m_Desc.bSrgbRead) { desc.Format = CTexture::ConvertToSRGBFmt(desc.Format); } switch (texType) { case eTT_1D: if (arraySize > 1) { desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY; desc.Texture1DArray.MostDetailedMip = rv.m_Desc.nMostDetailedMip; desc.Texture1DArray.MipLevels = nMipCount; desc.Texture1DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; desc.Texture1DArray.ArraySize = nSliceCount; } else { desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D; desc.Texture1D.MostDetailedMip = rv.m_Desc.nMostDetailedMip; desc.Texture1D.MipLevels = nMipCount; } break; case eTT_2D: if (arraySize > 1) { if (rv.m_Desc.bMultisample) { desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; desc.Texture2DMSArray.FirstArraySlice = rv.m_Desc.nFirstSlice; desc.Texture2DMSArray.ArraySize = nSliceCount; } else { desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; desc.Texture2DArray.MostDetailedMip = rv.m_Desc.nMostDetailedMip; desc.Texture2DArray.MipLevels = nMipCount; desc.Texture2DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; desc.Texture2DArray.ArraySize = nSliceCount; } } else { if (rv.m_Desc.bMultisample) { desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; } else { desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; desc.Texture2D.MostDetailedMip = rv.m_Desc.nMostDetailedMip; desc.Texture2D.MipLevels = nMipCount; } } break; case eTT_3D: desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; desc.Texture3D.MostDetailedMip = rv.m_Desc.nMostDetailedMip; desc.Texture3D.MipLevels = nMipCount; break; case eTT_Cube: desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; desc.TextureCube.MostDetailedMip = rv.m_Desc.nMostDetailedMip; desc.TextureCube.MipLevels = nMipCount; break; } } void SetRenderTargetViewDesc(const SResourceView& rv, uint32 texType, D3DFormat format, int arraySize, uint32 nSliceCount, D3D11_RENDER_TARGET_VIEW_DESC& rtvDesc) { ZeroStruct(rtvDesc); rtvDesc.Format = format; switch (texType) { case eTT_1D: if (arraySize > 1) { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY; rtvDesc.Texture1DArray.MipSlice = rv.m_Desc.nMostDetailedMip; rtvDesc.Texture1DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; rtvDesc.Texture1DArray.ArraySize = nSliceCount; } else { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D; rtvDesc.Texture1D.MipSlice = rv.m_Desc.nMostDetailedMip; } break; case eTT_2D: if (arraySize > 1) { if (rv.m_Desc.bMultisample) { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; rtvDesc.Texture2DMSArray.FirstArraySlice = rv.m_Desc.nFirstSlice; rtvDesc.Texture2DMSArray.ArraySize = nSliceCount; } else { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; rtvDesc.Texture2DArray.MipSlice = rv.m_Desc.nMostDetailedMip; rtvDesc.Texture2DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; rtvDesc.Texture2DArray.ArraySize = nSliceCount; } } else { if (rv.m_Desc.bMultisample) { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; } else { rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; rtvDesc.Texture2D.MipSlice = rv.m_Desc.nMostDetailedMip; } } break; case eTT_3D: rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; rtvDesc.Texture3D.MipSlice = rv.m_Desc.nMostDetailedMip; rtvDesc.Texture3D.FirstWSlice = rv.m_Desc.nFirstSlice; rtvDesc.Texture3D.WSize = nSliceCount; break; case eTT_Cube: rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; rtvDesc.Texture2DArray.MipSlice = rv.m_Desc.nMostDetailedMip; rtvDesc.Texture2DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; rtvDesc.Texture2DArray.ArraySize = nSliceCount; break; } } void SetDepthStencilViewDesc(const SResourceView& rv, uint32 texType, D3DFormat format, int arraySize, uint32 nSliceCount, D3D11_DEPTH_STENCIL_VIEW_DESC& dsvDesc) { ZeroStruct(dsvDesc); dsvDesc.Format = (DXGI_FORMAT)CTexture::ConvertToDepthStencilFmt(format); switch (texType) { case eTT_1D: if (arraySize > 1) { dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1DARRAY; dsvDesc.Texture1DArray.MipSlice = rv.m_Desc.nMostDetailedMip; dsvDesc.Texture1DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; dsvDesc.Texture1DArray.ArraySize = nSliceCount; } else { dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1D; dsvDesc.Texture1D.MipSlice = rv.m_Desc.nMostDetailedMip; } break; case eTT_2D: if (arraySize > 1) { if (rv.m_Desc.bMultisample) { dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; dsvDesc.Texture2DMSArray.FirstArraySlice = rv.m_Desc.nFirstSlice; dsvDesc.Texture2DMSArray.ArraySize = nSliceCount; } else { dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; dsvDesc.Texture2DArray.MipSlice = rv.m_Desc.nMostDetailedMip; dsvDesc.Texture2DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; dsvDesc.Texture2DArray.ArraySize = nSliceCount; } } else { if (rv.m_Desc.bMultisample) { dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; } else { dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; dsvDesc.Texture2D.MipSlice = rv.m_Desc.nMostDetailedMip; } } break; case eTT_Cube: { dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; dsvDesc.Texture2DArray.MipSlice = rv.m_Desc.nMostDetailedMip; dsvDesc.Texture2DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; dsvDesc.Texture2DArray.ArraySize = nSliceCount; } break; } } void SetUnorderedAccessViewDesc(const SResourceView& rv, uint32 texType, D3DFormat format, int arraySize, uint32 nSliceCount, D3D11_UNORDERED_ACCESS_VIEW_DESC& desc) { ZeroStruct(desc); desc.Format = format; switch (texType) { case eTT_1D: if (arraySize > 1) { desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1DARRAY; desc.Texture1DArray.MipSlice = rv.m_Desc.nMostDetailedMip; desc.Texture1DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; desc.Texture1DArray.ArraySize = nSliceCount; } else { desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1D; desc.Texture1D.MipSlice = rv.m_Desc.nMostDetailedMip; } break; case eTT_2D: if (arraySize > 1) { AZ_Assert(rv.m_Desc.bMultisample == 0, "No MSAA in UAV Array"); desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY; desc.Texture2DArray.MipSlice = rv.m_Desc.nMostDetailedMip; desc.Texture2DArray.FirstArraySlice = rv.m_Desc.nFirstSlice; desc.Texture2DArray.ArraySize = nSliceCount; } else { AZ_Assert(rv.m_Desc.bMultisample == 0, "No MSAA in UAV"); desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; desc.Texture2D.MipSlice = rv.m_Desc.nMostDetailedMip; } break; case eTT_3D: desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D; desc.Texture3D.MipSlice = rv.m_Desc.nMostDetailedMip; desc.Texture3D.FirstWSlice = rv.m_Desc.nFirstSlice; desc.Texture3D.WSize = nSliceCount; break; } } } RenderTargetData::~RenderTargetData() { CDeviceTexture* pTexMSAA = (CDeviceTexture*)m_pDeviceTextureMSAA; SAFE_RELEASE(pTexMSAA); for (size_t i = 0; i < m_ResourceViews.size(); ++i) { const SResourceView& rv = m_ResourceViews[i]; switch (rv.m_Desc.eViewType) { case SResourceView::eShaderResourceView: { D3DShaderResourceView* pView = static_cast(rv.m_pDeviceResourceView); SAFE_RELEASE(pView); break; } case SResourceView::eRenderTargetView: { D3DSurface* pView = static_cast(rv.m_pDeviceResourceView); SAFE_RELEASE(pView); break; } case SResourceView::eDepthStencilView: { D3DDepthSurface* pView = static_cast(rv.m_pDeviceResourceView); SAFE_RELEASE(pView); break; } case SResourceView::eUnorderedAccessView: { D3DUnorderedAccessView* pView = static_cast(rv.m_pDeviceResourceView); SAFE_RELEASE(pView); break; } default: assert(false); } } } //=============================================================================== #if defined(AZ_RESTRICTED_PLATFORM) #undef AZ_RESTRICTED_SECTION #define D3DTEXTURE_CPP_SECTION_1 1 #define D3DTEXTURE_CPP_SECTION_2 2 #define D3DTEXTURE_CPP_SECTION_3 3 #define D3DTEXTURE_CPP_SECTION_4 4 #define D3DTEXTURE_CPP_SECTION_5 5 #define D3DTEXTURE_CPP_SECTION_6 6 #define D3DTEXTURE_CPP_SECTION_7 7 #define D3DTEXTURE_CPP_SECTION_8 8 #define D3DTEXTURE_CPP_SECTION_9 9 #define D3DTEXTURE_CPP_SECTION_10 10 #define D3DTEXTURE_CPP_SECTION_11 11 #define D3DTEXTURE_CPP_SECTION_12 12 #endif #if defined(TEXTURE_GET_SYSTEM_COPY_SUPPORT) byte* CTexture::Convert(const byte* sourceData, int nWidth, int nHeight, int sourceMipCount, ETEX_Format eTFSrc, ETEX_Format eTFDst, int& nOutSize, bool bLinear) { nOutSize = 0; DXGI_FORMAT DeviceFormatSRC = (DXGI_FORMAT)DeviceFormatFromTexFormat(eTFSrc); DXGI_FORMAT DeviceFormatDST = (DXGI_FORMAT)DeviceFormatFromTexFormat(eTFDst); if (DeviceFormatSRC == DXGI_FORMAT_UNKNOWN || DeviceFormatDST == DXGI_FORMAT_UNKNOWN || nWidth <= 0 || nHeight <= 0) { AZ_Assert(false, "Invalid parameters to CTexture::Convert"); return nullptr; } if (sourceMipCount <= 0) { sourceMipCount = 1; } int outputSize = 0; byte* outputData = nullptr; if (eTFSrc == eTF_BC5U && eTFDst == eTF_BC3) { int w = nWidth; int h = nHeight; outputSize = CTexture::TextureDataSize(w, h, 1, sourceMipCount, 1, eTF_BC3); outputData = new byte[outputSize]; int nOffsDST = 0; int nOffsSRC = 0; for (int mip = 0; mip < sourceMipCount; mip++) { if (w <= 0) { w = 1; } if (h <= 0) { h = 1; } const void* outSrc = &sourceData[nOffsSRC]; DWORD outSize = CTexture::TextureDataSize(w, h, 1, 1, 1, eTFDst); nOffsSRC += CTexture::TextureDataSize(w, h, 1, 1, 1, eTFSrc); { const byte* src = (const byte*)outSrc; for (uint32 n = 0; n < outSize / 16; n++) // for each block { const uint8* srcDataBlock = &src[n * 16]; uint8* outputDataBlock = &outputData[nOffsDST + n * 16]; ConvertBlock3DcToDXT5(outputDataBlock, srcDataBlock); } nOffsDST += outSize; } w >>= 1; h >>= 1; } nOutSize = outputSize; return outputData; } outputSize = CTexture::TextureDataSize(nWidth, nHeight, 1, sourceMipCount, 1, eTFSrc); outputData = new byte[outputSize]; memcpy(outputData, sourceData, outputSize); nOutSize = outputSize; return outputData; } #endif //#if defined(WIN32) || defined(WIN64) D3DSurface* CTexture::GetSurface(int nCMSide, int nLevel) { if (!m_pDevTexture) { return NULL; } if (IsDeviceFormatTypeless(m_pPixelFormat->DeviceFormat)) { iLog->Log("Error: CTexture::GetSurface: typeless formats can't be specified for RTVs, failed to create surface for the texture %s", GetSourceName()); return NULL; } SCOPED_RENDERER_ALLOCATION_NAME_HINT(GetSourceName()); HRESULT hr = S_OK; D3DTexture* pID3DTexture = NULL; D3DTexture* pID3DTexture3D = NULL; D3DTexture* pID3DTextureCube = NULL; D3DSurface* pTargSurf = m_pDeviceRTV; const bool bUseMultisampledRTV = ((m_nFlags & FT_USAGE_MSAA) && m_bUseMultisampledRTV) != 0; if (bUseMultisampledRTV) { pTargSurf = m_pDeviceRTVMS; } if (!pTargSurf) { int nMipLevel = 0; int nSlice = 0; int nSliceCount = -1; if (m_eTT == eTT_Cube) { nMipLevel = (m_nFlags & FT_FORCE_MIPS) ? min((int)(m_nMips - 1), nLevel) : 0; nSlice = nCMSide; nSliceCount = 1; } pTargSurf = (D3DSurface*) CreateDeviceResourceView(SResourceView::RenderTargetView(m_eTFDst, nSlice, nSliceCount, nMipLevel, bUseMultisampledRTV)); if (bUseMultisampledRTV) { m_pDeviceRTVMS = pTargSurf; } else { m_pDeviceRTV = pTargSurf; } } assert(hr == S_OK); if (FAILED(hr)) { pTargSurf = NULL; } return pTargSurf; } void CTexture::Readback(AZ::u32 subresourceIndex, StagingHook callback) { if (m_pDevTexture) { m_pDevTexture->DownloadToStagingResource(subresourceIndex, callback); } } //=============================================================================== bool CTexture::IsDeviceFormatTypeless(D3DFormat nFormat) { switch (nFormat) { //128 bits case DXGI_FORMAT_R32G32B32A32_TYPELESS: case DXGI_FORMAT_R32G32B32_TYPELESS: //64 bits case DXGI_FORMAT_R16G16B16A16_TYPELESS: case DXGI_FORMAT_R32G32_TYPELESS: case DXGI_FORMAT_R32G8X24_TYPELESS: case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: //32 bits case DXGI_FORMAT_R10G10B10A2_TYPELESS: case DXGI_FORMAT_R8G8B8A8_TYPELESS: case DXGI_FORMAT_B8G8R8A8_TYPELESS: case DXGI_FORMAT_B8G8R8X8_TYPELESS: case DXGI_FORMAT_R16G16_TYPELESS: case DXGI_FORMAT_R32_TYPELESS: case DXGI_FORMAT_R24G8_TYPELESS: case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: case DXGI_FORMAT_X24_TYPELESS_G8_UINT: //16 bits case DXGI_FORMAT_R8G8_TYPELESS: case DXGI_FORMAT_R16_TYPELESS: //8 bits case DXGI_FORMAT_R8_TYPELESS: //block formats case DXGI_FORMAT_BC1_TYPELESS: case DXGI_FORMAT_BC2_TYPELESS: case DXGI_FORMAT_BC3_TYPELESS: case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC5_TYPELESS: #if defined(OPENGL) || defined(CRY_USE_METAL) case DXGI_FORMAT_ETC2_TYPELESS: case DXGI_FORMAT_ETC2A_TYPELESS: case DXGI_FORMAT_EAC_R11_TYPELESS: case DXGI_FORMAT_EAC_RG11_TYPELESS: #endif #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_1 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else case DXGI_FORMAT_BC6H_TYPELESS: #endif case DXGI_FORMAT_BC7_TYPELESS: #ifdef CRY_USE_METAL case DXGI_FORMAT_PVRTC2_TYPELESS: case DXGI_FORMAT_PVRTC4_TYPELESS: #endif #if defined(ANDROID) || defined(CRY_USE_METAL) case DXGI_FORMAT_ASTC_4x4_TYPELESS: case DXGI_FORMAT_ASTC_5x4_TYPELESS: case DXGI_FORMAT_ASTC_5x5_TYPELESS: case DXGI_FORMAT_ASTC_6x5_TYPELESS: case DXGI_FORMAT_ASTC_6x6_TYPELESS: case DXGI_FORMAT_ASTC_8x5_TYPELESS: case DXGI_FORMAT_ASTC_8x6_TYPELESS: case DXGI_FORMAT_ASTC_8x8_TYPELESS: case DXGI_FORMAT_ASTC_10x5_TYPELESS: case DXGI_FORMAT_ASTC_10x6_TYPELESS: case DXGI_FORMAT_ASTC_10x8_TYPELESS: case DXGI_FORMAT_ASTC_10x10_TYPELESS: case DXGI_FORMAT_ASTC_12x10_TYPELESS: case DXGI_FORMAT_ASTC_12x12_TYPELESS: #endif return true; default: break; } return false; } bool CTexture::IsDeviceFormatSRGBReadable(D3DFormat nFormat) { switch (nFormat) { case DXGI_FORMAT_R8G8B8A8_UNORM: return true; case DXGI_FORMAT_B8G8R8A8_UNORM: return true; case DXGI_FORMAT_B8G8R8X8_UNORM: return true; case DXGI_FORMAT_BC1_UNORM: return true; case DXGI_FORMAT_BC2_UNORM: return true; case DXGI_FORMAT_BC3_UNORM: return true; case DXGI_FORMAT_BC7_UNORM: return true; #if defined(OPENGL) || defined(CRY_USE_METAL) case DXGI_FORMAT_ETC2_UNORM: return true; case DXGI_FORMAT_ETC2A_UNORM: return true; #endif //defined(OPENGL) #ifdef CRY_USE_METAL case DXGI_FORMAT_PVRTC2_UNORM: return true; case DXGI_FORMAT_PVRTC4_UNORM: return true; #endif #if defined(ANDROID) || defined(CRY_USE_METAL) case DXGI_FORMAT_ASTC_4x4_UNORM: return true; case DXGI_FORMAT_ASTC_5x4_UNORM: return true; case DXGI_FORMAT_ASTC_5x5_UNORM: return true; case DXGI_FORMAT_ASTC_6x5_UNORM: return true; case DXGI_FORMAT_ASTC_6x6_UNORM: return true; case DXGI_FORMAT_ASTC_8x5_UNORM: return true; case DXGI_FORMAT_ASTC_8x6_UNORM: return true; case DXGI_FORMAT_ASTC_8x8_UNORM: return true; case DXGI_FORMAT_ASTC_10x5_UNORM: return true; case DXGI_FORMAT_ASTC_10x6_UNORM: return true; case DXGI_FORMAT_ASTC_10x8_UNORM: return true; case DXGI_FORMAT_ASTC_10x10_UNORM: return true; case DXGI_FORMAT_ASTC_12x10_UNORM: return true; case DXGI_FORMAT_ASTC_12x12_UNORM: return true; #endif default: break; } return false; } // this function is valid for FT_USAGE_DEPTHSTENCIL textures only D3DFormat CTexture::DeviceFormatFromTexFormat(ETEX_Format eTF) { switch (eTF) { case eTF_R8G8B8A8: return DXGI_FORMAT_R8G8B8A8_UNORM; case eTF_R8G8B8A8S: return DXGI_FORMAT_R8G8B8A8_SNORM; case eTF_A8: return DXGI_FORMAT_A8_UNORM; case eTF_R8: return DXGI_FORMAT_R8_UNORM; case eTF_R8S: return DXGI_FORMAT_R8_SNORM; case eTF_R16: return DXGI_FORMAT_R16_UNORM; case eTF_R16U: return DXGI_FORMAT_R16_UINT; case eTF_R16G16U: return DXGI_FORMAT_R16G16_UINT; case eTF_R10G10B10A2UI: return DXGI_FORMAT_R10G10B10A2_UINT; case eTF_R16F: return DXGI_FORMAT_R16_FLOAT; case eTF_R32F: return DXGI_FORMAT_R32_FLOAT; case eTF_R8G8: return DXGI_FORMAT_R8G8_UNORM; case eTF_R8G8S: return DXGI_FORMAT_R8G8_SNORM; case eTF_R16G16: return DXGI_FORMAT_R16G16_UNORM; case eTF_R16G16S: return DXGI_FORMAT_R16G16_SNORM; case eTF_R16G16F: return DXGI_FORMAT_R16G16_FLOAT; case eTF_R11G11B10F: return DXGI_FORMAT_R11G11B10_FLOAT; case eTF_R10G10B10A2: return DXGI_FORMAT_R10G10B10A2_UNORM; case eTF_R16G16B16A16: return DXGI_FORMAT_R16G16B16A16_UNORM; case eTF_R16G16B16A16S: return DXGI_FORMAT_R16G16B16A16_SNORM; case eTF_R16G16B16A16F: return DXGI_FORMAT_R16G16B16A16_FLOAT; case eTF_R32G32B32A32F: return DXGI_FORMAT_R32G32B32A32_FLOAT; case eTF_BC1: return DXGI_FORMAT_BC1_UNORM; case eTF_BC2: return DXGI_FORMAT_BC2_UNORM; case eTF_BC3: return DXGI_FORMAT_BC3_UNORM; case eTF_BC4U: return DXGI_FORMAT_BC4_UNORM; case eTF_BC4S: return DXGI_FORMAT_BC4_SNORM; case eTF_BC5U: return DXGI_FORMAT_BC5_UNORM; case eTF_BC5S: return DXGI_FORMAT_BC5_SNORM; case eTF_BC6UH: return DXGI_FORMAT_BC6H_UF16; case eTF_BC6SH: return DXGI_FORMAT_BC6H_SF16; case eTF_BC7: return DXGI_FORMAT_BC7_UNORM; case eTF_R9G9B9E5: return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; // hardware depth buffers case eTF_D16: return DXGI_FORMAT_D16_UNORM; case eTF_D24S8: return DXGI_FORMAT_D24_UNORM_S8_UINT; case eTF_D32F: return DXGI_FORMAT_D32_FLOAT; case eTF_D32FS8: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; // only available as hardware format under DX11.1 with DXGI 1.2 case eTF_B5G6R5: return DXGI_FORMAT_B5G6R5_UNORM; case eTF_B5G5R5: return DXGI_FORMAT_B5G5R5A1_UNORM; // case eTF_B4G4R4A4: return DXGI_FORMAT_B4G4R4A4_UNORM; case eTF_B4G4R4A4: return DXGI_FORMAT_UNKNOWN; #if defined(OPENGL) || defined(CRY_USE_METAL) // only available as hardware format under OpenGL case eTF_EAC_R11: return DXGI_FORMAT_EAC_R11_UNORM; case eTF_EAC_RG11: return DXGI_FORMAT_EAC_RG11_UNORM; case eTF_ETC2: return DXGI_FORMAT_ETC2_UNORM; case eTF_ETC2A: return DXGI_FORMAT_ETC2A_UNORM; #endif //defined(OPENGL) #ifdef CRY_USE_METAL case eTF_PVRTC2: return DXGI_FORMAT_PVRTC2_UNORM; case eTF_PVRTC4: return DXGI_FORMAT_PVRTC4_UNORM; #endif #if defined(ANDROID) || defined(CRY_USE_METAL) case eTF_ASTC_4x4: return DXGI_FORMAT_ASTC_4x4_UNORM; case eTF_ASTC_5x4: return DXGI_FORMAT_ASTC_5x4_UNORM; case eTF_ASTC_5x5: return DXGI_FORMAT_ASTC_5x5_UNORM; case eTF_ASTC_6x5: return DXGI_FORMAT_ASTC_6x5_UNORM; case eTF_ASTC_6x6: return DXGI_FORMAT_ASTC_6x6_UNORM; case eTF_ASTC_8x5: return DXGI_FORMAT_ASTC_8x5_UNORM; case eTF_ASTC_8x6: return DXGI_FORMAT_ASTC_8x6_UNORM; case eTF_ASTC_8x8: return DXGI_FORMAT_ASTC_8x8_UNORM; case eTF_ASTC_10x5: return DXGI_FORMAT_ASTC_10x5_UNORM; case eTF_ASTC_10x6: return DXGI_FORMAT_ASTC_10x6_UNORM; case eTF_ASTC_10x8: return DXGI_FORMAT_ASTC_10x8_UNORM; case eTF_ASTC_10x10: return DXGI_FORMAT_ASTC_10x10_UNORM; case eTF_ASTC_12x10: return DXGI_FORMAT_ASTC_12x10_UNORM; case eTF_ASTC_12x12: return DXGI_FORMAT_ASTC_12x12_UNORM; #endif // only available as hardware format under DX9 case eTF_A8L8: return DXGI_FORMAT_UNKNOWN; case eTF_L8: return DXGI_FORMAT_UNKNOWN; case eTF_L8V8U8: return DXGI_FORMAT_UNKNOWN; case eTF_B8G8R8: return DXGI_FORMAT_UNKNOWN; case eTF_L8V8U8X8: return DXGI_FORMAT_UNKNOWN; case eTF_B8G8R8X8: return DXGI_FORMAT_B8G8R8X8_UNORM; case eTF_B8G8R8A8: return DXGI_FORMAT_B8G8R8A8_UNORM; } return DXGI_FORMAT_UNKNOWN; } D3DFormat CTexture::GetD3DLinFormat(D3DFormat nFormat) { return nFormat; } D3DFormat CTexture::ConvertToSRGBFmt(D3DFormat fmt) { switch (fmt) { case DXGI_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; case DXGI_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; case DXGI_FORMAT_B8G8R8X8_UNORM: return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; case DXGI_FORMAT_BC1_UNORM: return DXGI_FORMAT_BC1_UNORM_SRGB; case DXGI_FORMAT_BC2_UNORM: return DXGI_FORMAT_BC2_UNORM_SRGB; case DXGI_FORMAT_BC3_UNORM: return DXGI_FORMAT_BC3_UNORM_SRGB; case DXGI_FORMAT_BC7_UNORM: return DXGI_FORMAT_BC7_UNORM_SRGB; #if defined(OPENGL) || defined(CRY_USE_METAL) case DXGI_FORMAT_ETC2_UNORM: return DXGI_FORMAT_ETC2_UNORM_SRGB; case DXGI_FORMAT_ETC2A_UNORM: return DXGI_FORMAT_ETC2A_UNORM_SRGB; case DXGI_FORMAT_EAC_RG11_UNORM: return DXGI_FORMAT_EAC_RG11_UNORM; #endif //defined(OPENGL) #ifdef CRY_USE_METAL case DXGI_FORMAT_PVRTC2_UNORM: return DXGI_FORMAT_PVRTC2_UNORM_SRGB; case DXGI_FORMAT_PVRTC4_UNORM: return DXGI_FORMAT_PVRTC4_UNORM_SRGB; #endif #if defined(ANDROID) || defined(CRY_USE_METAL) case DXGI_FORMAT_ASTC_4x4_UNORM: return DXGI_FORMAT_ASTC_4x4_UNORM_SRGB; case DXGI_FORMAT_ASTC_5x4_UNORM: return DXGI_FORMAT_ASTC_5x4_UNORM_SRGB; case DXGI_FORMAT_ASTC_5x5_UNORM: return DXGI_FORMAT_ASTC_5x5_UNORM_SRGB; case DXGI_FORMAT_ASTC_6x5_UNORM: return DXGI_FORMAT_ASTC_6x5_UNORM_SRGB; case DXGI_FORMAT_ASTC_6x6_UNORM: return DXGI_FORMAT_ASTC_6x6_UNORM_SRGB; case DXGI_FORMAT_ASTC_8x5_UNORM: return DXGI_FORMAT_ASTC_8x5_UNORM_SRGB; case DXGI_FORMAT_ASTC_8x6_UNORM: return DXGI_FORMAT_ASTC_8x6_UNORM_SRGB; case DXGI_FORMAT_ASTC_8x8_UNORM: return DXGI_FORMAT_ASTC_8x8_UNORM_SRGB; case DXGI_FORMAT_ASTC_10x5_UNORM: return DXGI_FORMAT_ASTC_10x5_UNORM_SRGB; case DXGI_FORMAT_ASTC_10x6_UNORM: return DXGI_FORMAT_ASTC_10x6_UNORM_SRGB; case DXGI_FORMAT_ASTC_10x8_UNORM: return DXGI_FORMAT_ASTC_10x8_UNORM_SRGB; case DXGI_FORMAT_ASTC_10x10_UNORM: return DXGI_FORMAT_ASTC_10x10_UNORM_SRGB; case DXGI_FORMAT_ASTC_12x10_UNORM: return DXGI_FORMAT_ASTC_12x10_UNORM_SRGB; case DXGI_FORMAT_ASTC_12x12_UNORM: return DXGI_FORMAT_ASTC_12x12_UNORM_SRGB; case DXGI_FORMAT_R8_UNORM: return DXGI_FORMAT_R8_UNORM; case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; #endif case DXGI_FORMAT_R10G10B10A2_UNORM: return DXGI_FORMAT_R10G10B10A2_UNORM; // AntonK: we don't need sRGB space for fp formats, because there is enough precision case DXGI_FORMAT_R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; case DXGI_FORMAT_R11G11B10_FLOAT: return DXGI_FORMAT_R11G11B10_FLOAT; // There is no SRGB format for BC4 case DXGI_FORMAT_BC4_SNORM: return DXGI_FORMAT_BC4_SNORM; case DXGI_FORMAT_BC4_UNORM: return DXGI_FORMAT_BC4_UNORM; default: assert(0); } return fmt; } D3DFormat CTexture::ConvertToSignedFmt(D3DFormat fmt) { switch (fmt) { case DXGI_FORMAT_R8_UNORM: return DXGI_FORMAT_R8_SNORM; case DXGI_FORMAT_R8G8_UNORM: return DXGI_FORMAT_R8G8_SNORM; case DXGI_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_SNORM; case DXGI_FORMAT_R16_UNORM: return DXGI_FORMAT_R16_SNORM; case DXGI_FORMAT_R16G16_UNORM: return DXGI_FORMAT_R16G16_SNORM; case DXGI_FORMAT_R16G16B16A16_UNORM: return DXGI_FORMAT_R16G16B16A16_SNORM; case DXGI_FORMAT_BC4_UNORM: return DXGI_FORMAT_BC4_SNORM; case DXGI_FORMAT_BC5_UNORM: return DXGI_FORMAT_BC5_SNORM; case DXGI_FORMAT_BC6H_UF16: return DXGI_FORMAT_BC6H_SF16; case DXGI_FORMAT_R32G32B32A32_UINT: return DXGI_FORMAT_R32G32B32A32_SINT; case DXGI_FORMAT_R32G32B32_UINT: return DXGI_FORMAT_R32G32B32_SINT; case DXGI_FORMAT_R16G16B16A16_UINT: return DXGI_FORMAT_R16G16B16A16_SINT; case DXGI_FORMAT_R32G32_UINT: return DXGI_FORMAT_R32G32_SINT; case DXGI_FORMAT_R8G8B8A8_UINT: return DXGI_FORMAT_R8G8B8A8_SINT; case DXGI_FORMAT_R16G16_UINT: return DXGI_FORMAT_R16G16_SINT; case DXGI_FORMAT_R32_UINT: return DXGI_FORMAT_R32_SINT; case DXGI_FORMAT_R8G8_UINT: return DXGI_FORMAT_R8G8_SINT; case DXGI_FORMAT_R16_UINT: return DXGI_FORMAT_R16_SINT; case DXGI_FORMAT_R8_UINT: return DXGI_FORMAT_R8_SINT; default: assert(0); } return fmt; } ETEX_Format CTexture::TexFormatFromDeviceFormat(D3DFormat nFormat) { switch (nFormat) { case DXGI_FORMAT_R8G8B8A8_TYPELESS: return eTF_R8G8B8A8; case DXGI_FORMAT_R8G8B8A8_UNORM: return eTF_R8G8B8A8; case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return eTF_R8G8B8A8; case DXGI_FORMAT_R8G8B8A8_SNORM: return eTF_R8G8B8A8S; case DXGI_FORMAT_A8_UNORM: return eTF_A8; case DXGI_FORMAT_R8_TYPELESS: case DXGI_FORMAT_R8_UNORM: return eTF_R8; case DXGI_FORMAT_R8_SNORM: return eTF_R8S; case DXGI_FORMAT_R16_UNORM: return eTF_R16; case DXGI_FORMAT_R16_UINT: return eTF_R16U; case DXGI_FORMAT_R16G16_UINT: return eTF_R16G16U; case DXGI_FORMAT_R10G10B10A2_UINT: return eTF_R10G10B10A2UI; case DXGI_FORMAT_R16_FLOAT: return eTF_R16F; case DXGI_FORMAT_R16_TYPELESS: return eTF_R16F; case DXGI_FORMAT_R32_FLOAT: return eTF_R32F; case DXGI_FORMAT_R32_TYPELESS: return eTF_R32F; case DXGI_FORMAT_R8G8_UNORM: return eTF_R8G8; case DXGI_FORMAT_R8G8_SNORM: return eTF_R8G8S; case DXGI_FORMAT_R16G16_UNORM: return eTF_R16G16; case DXGI_FORMAT_R16G16_SNORM: return eTF_R16G16S; case DXGI_FORMAT_R16G16_FLOAT: return eTF_R16G16F; case DXGI_FORMAT_R11G11B10_FLOAT: return eTF_R11G11B10F; case DXGI_FORMAT_R10G10B10A2_UNORM: return eTF_R10G10B10A2; case DXGI_FORMAT_R10G10B10A2_TYPELESS: return eTF_R10G10B10A2; case DXGI_FORMAT_R16G16B16A16_UNORM: return eTF_R16G16B16A16; case DXGI_FORMAT_R16G16B16A16_SNORM: return eTF_R16G16B16A16S; case DXGI_FORMAT_R16G16B16A16_FLOAT: return eTF_R16G16B16A16F; case DXGI_FORMAT_R16G16B16A16_TYPELESS: return eTF_R16G16B16A16F; case DXGI_FORMAT_R32G32B32A32_FLOAT: return eTF_R32G32B32A32F; case DXGI_FORMAT_R32G32B32A32_TYPELESS: return eTF_R32G32B32A32F; case DXGI_FORMAT_BC1_TYPELESS: return eTF_BC1; case DXGI_FORMAT_BC1_UNORM: return eTF_BC1; case DXGI_FORMAT_BC1_UNORM_SRGB: return eTF_BC1; case DXGI_FORMAT_BC2_TYPELESS: return eTF_BC2; case DXGI_FORMAT_BC2_UNORM: return eTF_BC2; case DXGI_FORMAT_BC2_UNORM_SRGB: return eTF_BC2; case DXGI_FORMAT_BC3_TYPELESS: return eTF_BC3; case DXGI_FORMAT_BC3_UNORM: return eTF_BC3; case DXGI_FORMAT_BC3_UNORM_SRGB: return eTF_BC3; case DXGI_FORMAT_BC4_TYPELESS: return eTF_BC4U; case DXGI_FORMAT_BC4_UNORM: return eTF_BC4U; case DXGI_FORMAT_BC4_SNORM: return eTF_BC4S; case DXGI_FORMAT_BC5_TYPELESS: return eTF_BC5U; case DXGI_FORMAT_BC5_UNORM: return eTF_BC5U; case DXGI_FORMAT_BC5_SNORM: return eTF_BC5S; case DXGI_FORMAT_BC6H_UF16: return eTF_BC6UH; case DXGI_FORMAT_BC6H_SF16: return eTF_BC6SH; case DXGI_FORMAT_BC7_TYPELESS: return eTF_BC7; case DXGI_FORMAT_BC7_UNORM: return eTF_BC7; case DXGI_FORMAT_BC7_UNORM_SRGB: return eTF_BC7; case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: return eTF_R9G9B9E5; // hardware depth buffers case DXGI_FORMAT_D16_UNORM: return eTF_D16; case DXGI_FORMAT_D24_UNORM_S8_UINT: return eTF_D24S8; case DXGI_FORMAT_D32_FLOAT: return eTF_D32F; case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return eTF_D32FS8; case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return eTF_D24S8; case DXGI_FORMAT_R24G8_TYPELESS: return eTF_D24S8; case DXGI_FORMAT_R32G8X24_TYPELESS: return eTF_D32FS8; case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: return eTF_D32FS8; // only available as hardware format under DX11.1 with DXGI 1.2 case DXGI_FORMAT_B5G6R5_UNORM: return eTF_B5G6R5; case DXGI_FORMAT_B5G5R5A1_UNORM: return eTF_B5G5R5; // case DXGI_FORMAT_B4G4R4A4_UNORM: return eTF_B4G4R4A4; #if defined(OPENGL) || defined(CRY_USE_METAL) // only available as hardware format under OpenGL case DXGI_FORMAT_EAC_R11_UNORM: case DXGI_FORMAT_EAC_R11_TYPELESS: return eTF_EAC_R11; case DXGI_FORMAT_EAC_RG11_UNORM: case DXGI_FORMAT_EAC_RG11_TYPELESS: return eTF_EAC_RG11; case DXGI_FORMAT_ETC2_UNORM: case DXGI_FORMAT_ETC2_UNORM_SRGB: case DXGI_FORMAT_ETC2_TYPELESS: return eTF_ETC2; case DXGI_FORMAT_ETC2A_UNORM: case DXGI_FORMAT_ETC2A_UNORM_SRGB: case DXGI_FORMAT_ETC2A_TYPELESS: return eTF_ETC2A; #endif //defined(OPENGL) #ifdef CRY_USE_METAL case DXGI_FORMAT_PVRTC2_TYPELESS: case DXGI_FORMAT_PVRTC2_UNORM: case DXGI_FORMAT_PVRTC2_UNORM_SRGB: return eTF_PVRTC2; case DXGI_FORMAT_PVRTC4_TYPELESS: case DXGI_FORMAT_PVRTC4_UNORM: case DXGI_FORMAT_PVRTC4_UNORM_SRGB: return eTF_PVRTC4; #endif #if defined(ANDROID) || defined(CRY_USE_METAL) case DXGI_FORMAT_ASTC_4x4_TYPELESS: case DXGI_FORMAT_ASTC_4x4_UNORM: case DXGI_FORMAT_ASTC_4x4_UNORM_SRGB: return eTF_ASTC_4x4; case DXGI_FORMAT_ASTC_5x4_TYPELESS: case DXGI_FORMAT_ASTC_5x4_UNORM: case DXGI_FORMAT_ASTC_5x4_UNORM_SRGB: return eTF_ASTC_5x4; case DXGI_FORMAT_ASTC_5x5_TYPELESS: case DXGI_FORMAT_ASTC_5x5_UNORM: case DXGI_FORMAT_ASTC_5x5_UNORM_SRGB: return eTF_ASTC_5x5; case DXGI_FORMAT_ASTC_6x5_TYPELESS: case DXGI_FORMAT_ASTC_6x5_UNORM: case DXGI_FORMAT_ASTC_6x5_UNORM_SRGB: return eTF_ASTC_6x5; case DXGI_FORMAT_ASTC_6x6_TYPELESS: case DXGI_FORMAT_ASTC_6x6_UNORM: case DXGI_FORMAT_ASTC_6x6_UNORM_SRGB: return eTF_ASTC_6x6; case DXGI_FORMAT_ASTC_8x5_TYPELESS: case DXGI_FORMAT_ASTC_8x5_UNORM: case DXGI_FORMAT_ASTC_8x5_UNORM_SRGB: return eTF_ASTC_8x5; case DXGI_FORMAT_ASTC_8x6_TYPELESS: case DXGI_FORMAT_ASTC_8x6_UNORM: case DXGI_FORMAT_ASTC_8x6_UNORM_SRGB: return eTF_ASTC_8x6; case DXGI_FORMAT_ASTC_8x8_TYPELESS: case DXGI_FORMAT_ASTC_8x8_UNORM: case DXGI_FORMAT_ASTC_8x8_UNORM_SRGB: return eTF_ASTC_8x8; case DXGI_FORMAT_ASTC_10x5_TYPELESS: case DXGI_FORMAT_ASTC_10x5_UNORM: case DXGI_FORMAT_ASTC_10x5_UNORM_SRGB: return eTF_ASTC_10x5; case DXGI_FORMAT_ASTC_10x6_TYPELESS: case DXGI_FORMAT_ASTC_10x6_UNORM: case DXGI_FORMAT_ASTC_10x6_UNORM_SRGB: return eTF_ASTC_10x6; case DXGI_FORMAT_ASTC_10x8_TYPELESS: case DXGI_FORMAT_ASTC_10x8_UNORM: case DXGI_FORMAT_ASTC_10x8_UNORM_SRGB: return eTF_ASTC_10x8; case DXGI_FORMAT_ASTC_10x10_TYPELESS: case DXGI_FORMAT_ASTC_10x10_UNORM: case DXGI_FORMAT_ASTC_10x10_UNORM_SRGB: return eTF_ASTC_10x10; case DXGI_FORMAT_ASTC_12x10_TYPELESS: case DXGI_FORMAT_ASTC_12x10_UNORM: case DXGI_FORMAT_ASTC_12x10_UNORM_SRGB: return eTF_ASTC_12x10; case DXGI_FORMAT_ASTC_12x12_TYPELESS: case DXGI_FORMAT_ASTC_12x12_UNORM: case DXGI_FORMAT_ASTC_12x12_UNORM_SRGB: return eTF_ASTC_12x12; #endif // only available as hardware format under DX9 case DXGI_FORMAT_B8G8R8A8_TYPELESS: return eTF_B8G8R8A8; case DXGI_FORMAT_B8G8R8A8_UNORM: return eTF_B8G8R8A8; case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return eTF_B8G8R8A8; case DXGI_FORMAT_B8G8R8X8_TYPELESS: return eTF_B8G8R8X8; case DXGI_FORMAT_B8G8R8X8_UNORM: return eTF_B8G8R8X8; case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return eTF_B8G8R8X8; default: assert(0); } return eTF_Unknown; } // this function is valid for FT_USAGE_DEPTHSTENCIL textures only D3DFormat CTexture::ConvertToDepthStencilFmt(D3DFormat nFormat) { switch (nFormat) { 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; // Don't assert if they pass in a valid depth format... case DXGI_FORMAT_D16_UNORM: case DXGI_FORMAT_D24_UNORM_S8_UINT: case DXGI_FORMAT_D32_FLOAT: case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return nFormat; default: assert(nFormat == DXGI_FORMAT_D16_UNORM || nFormat == DXGI_FORMAT_D24_UNORM_S8_UINT || nFormat == DXGI_FORMAT_D32_FLOAT || nFormat == DXGI_FORMAT_D32_FLOAT_S8X24_UINT); } return nFormat; } D3DFormat CTexture::ConvertToStencilFmt(D3DFormat nFormat) { switch (nFormat) { case DXGI_FORMAT_R32G8X24_TYPELESS: return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; case DXGI_FORMAT_R24G8_TYPELESS: return DXGI_FORMAT_X24_TYPELESS_G8_UINT; default: assert(nFormat == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT || nFormat == DXGI_FORMAT_X24_TYPELESS_G8_UINT); } return nFormat; } D3DFormat CTexture::ConvertToShaderResourceFmt(D3DFormat nFormat) { //handle special cases switch (nFormat) { 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; // case DXGI_FORMAT_R32G32_TYPELESS: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; default: break; //pass through } return nFormat; } D3DFormat CTexture::ConvertToTypelessFmt(D3DFormat fmt) { switch (fmt) { case DXGI_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_TYPELESS; case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_TYPELESS; case DXGI_FORMAT_R8G8B8A8_SNORM: return DXGI_FORMAT_R8G8B8A8_TYPELESS; case DXGI_FORMAT_R8G8B8A8_UINT: return DXGI_FORMAT_R8G8B8A8_TYPELESS; case DXGI_FORMAT_R8G8B8A8_SINT: return DXGI_FORMAT_R8G8B8A8_TYPELESS; case DXGI_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_TYPELESS; case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_TYPELESS; case DXGI_FORMAT_B8G8R8X8_UNORM: return DXGI_FORMAT_B8G8R8X8_TYPELESS; case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8X8_TYPELESS; case DXGI_FORMAT_R8_UNORM: return DXGI_FORMAT_R8_TYPELESS; case DXGI_FORMAT_R8_SNORM: return DXGI_FORMAT_R8_TYPELESS; case DXGI_FORMAT_R8_UINT: return DXGI_FORMAT_R8_TYPELESS; case DXGI_FORMAT_R8_SINT: return DXGI_FORMAT_R8_TYPELESS; case DXGI_FORMAT_R16_UNORM: return DXGI_FORMAT_R16_TYPELESS; case DXGI_FORMAT_R16_SNORM: return DXGI_FORMAT_R16_TYPELESS; case DXGI_FORMAT_R16_FLOAT: return DXGI_FORMAT_R16_TYPELESS; case DXGI_FORMAT_R16_UINT: return DXGI_FORMAT_R16_TYPELESS; case DXGI_FORMAT_R16_SINT: return DXGI_FORMAT_R16_TYPELESS; case DXGI_FORMAT_R32_FLOAT: return DXGI_FORMAT_R32_TYPELESS; case DXGI_FORMAT_R32_UINT: return DXGI_FORMAT_R32_TYPELESS; case DXGI_FORMAT_R32_SINT: return DXGI_FORMAT_R32_TYPELESS; case DXGI_FORMAT_R8G8_UNORM: return DXGI_FORMAT_R8G8_TYPELESS; case DXGI_FORMAT_R8G8_SNORM: return DXGI_FORMAT_R8G8_TYPELESS; case DXGI_FORMAT_R8G8_UINT: return DXGI_FORMAT_R8G8_TYPELESS; case DXGI_FORMAT_R8G8_SINT: return DXGI_FORMAT_R8G8_TYPELESS; case DXGI_FORMAT_R16G16_FLOAT: return DXGI_FORMAT_R16G16_TYPELESS; case DXGI_FORMAT_R16G16_UNORM: return DXGI_FORMAT_R16G16_TYPELESS; case DXGI_FORMAT_R16G16_SNORM: return DXGI_FORMAT_R16G16_TYPELESS; case DXGI_FORMAT_R16G16_UINT: return DXGI_FORMAT_R16G16_TYPELESS; case DXGI_FORMAT_R16G16_SINT: return DXGI_FORMAT_R16G16_TYPELESS; case DXGI_FORMAT_R32G32_FLOAT: return DXGI_FORMAT_R32G32_TYPELESS; case DXGI_FORMAT_R32G32_UINT: return DXGI_FORMAT_R32G32_TYPELESS; case DXGI_FORMAT_R32G32_SINT: return DXGI_FORMAT_R32G32_TYPELESS; case DXGI_FORMAT_R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_TYPELESS; case DXGI_FORMAT_R32G32B32_UINT: return DXGI_FORMAT_R32G32B32_TYPELESS; case DXGI_FORMAT_R32G32B32_SINT: return DXGI_FORMAT_R32G32B32_TYPELESS; case DXGI_FORMAT_R10G10B10A2_UNORM: return DXGI_FORMAT_R10G10B10A2_TYPELESS; case DXGI_FORMAT_R10G10B10A2_UINT: return DXGI_FORMAT_R10G10B10A2_TYPELESS; case DXGI_FORMAT_R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_TYPELESS; case DXGI_FORMAT_R16G16B16A16_UNORM: return DXGI_FORMAT_R16G16B16A16_TYPELESS; case DXGI_FORMAT_R16G16B16A16_SNORM: return DXGI_FORMAT_R16G16B16A16_TYPELESS; case DXGI_FORMAT_R16G16B16A16_UINT: return DXGI_FORMAT_R16G16B16A16_TYPELESS; case DXGI_FORMAT_R16G16B16A16_SINT: return DXGI_FORMAT_R16G16B16A16_TYPELESS; case DXGI_FORMAT_R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_TYPELESS; case DXGI_FORMAT_R32G32B32A32_UINT: return DXGI_FORMAT_R32G32B32A32_TYPELESS; case DXGI_FORMAT_R32G32B32A32_SINT: return DXGI_FORMAT_R32G32B32A32_TYPELESS; case DXGI_FORMAT_BC1_UNORM: return DXGI_FORMAT_BC1_TYPELESS; case DXGI_FORMAT_BC1_UNORM_SRGB: return DXGI_FORMAT_BC1_TYPELESS; case DXGI_FORMAT_BC2_UNORM: return DXGI_FORMAT_BC2_TYPELESS; case DXGI_FORMAT_BC2_UNORM_SRGB: return DXGI_FORMAT_BC2_TYPELESS; case DXGI_FORMAT_BC3_UNORM: return DXGI_FORMAT_BC3_TYPELESS; case DXGI_FORMAT_BC3_UNORM_SRGB: return DXGI_FORMAT_BC3_TYPELESS; case DXGI_FORMAT_BC4_UNORM: return DXGI_FORMAT_BC4_TYPELESS; case DXGI_FORMAT_BC4_SNORM: return DXGI_FORMAT_BC4_TYPELESS; case DXGI_FORMAT_BC5_UNORM: return DXGI_FORMAT_BC5_TYPELESS; case DXGI_FORMAT_BC5_SNORM: return DXGI_FORMAT_BC5_TYPELESS; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_2 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else case DXGI_FORMAT_BC6H_UF16: return DXGI_FORMAT_BC6H_TYPELESS; case DXGI_FORMAT_BC6H_SF16: return DXGI_FORMAT_BC6H_TYPELESS; #endif case DXGI_FORMAT_BC7_UNORM: return DXGI_FORMAT_BC7_TYPELESS; case DXGI_FORMAT_BC7_UNORM_SRGB: return DXGI_FORMAT_BC7_TYPELESS; #if defined(OPENGL) && !defined(CRY_USE_METAL) case DXGI_FORMAT_EAC_R11_UNORM: return DXGI_FORMAT_EAC_R11_TYPELESS; case DXGI_FORMAT_EAC_R11_SNORM: return DXGI_FORMAT_EAC_R11_TYPELESS; case DXGI_FORMAT_EAC_RG11_UNORM: return DXGI_FORMAT_EAC_RG11_TYPELESS; case DXGI_FORMAT_EAC_RG11_SNORM: return DXGI_FORMAT_EAC_RG11_TYPELESS; case DXGI_FORMAT_ETC2_UNORM: return DXGI_FORMAT_ETC2_TYPELESS; case DXGI_FORMAT_ETC2_UNORM_SRGB: return DXGI_FORMAT_ETC2_TYPELESS; case DXGI_FORMAT_ETC2A_UNORM: return DXGI_FORMAT_ETC2A_TYPELESS; case DXGI_FORMAT_ETC2A_UNORM_SRGB: return DXGI_FORMAT_ETC2A_TYPELESS; #endif //defined(OPENGL) case DXGI_FORMAT_D16_UNORM: return DXGI_FORMAT_R16_TYPELESS; case DXGI_FORMAT_D24_UNORM_S8_UINT: return DXGI_FORMAT_R24G8_TYPELESS; case DXGI_FORMAT_D32_FLOAT: return DXGI_FORMAT_R32_TYPELESS; case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return DXGI_FORMAT_R32G8X24_TYPELESS; // todo: add missing formats if they found required #ifdef CRY_USE_METAL case DXGI_FORMAT_PVRTC2_UNORM: case DXGI_FORMAT_PVRTC2_UNORM_SRGB: return DXGI_FORMAT_PVRTC2_TYPELESS; case DXGI_FORMAT_PVRTC4_UNORM: case DXGI_FORMAT_PVRTC4_UNORM_SRGB: return DXGI_FORMAT_PVRTC4_TYPELESS; #endif #if defined(ANDROID) || defined(CRY_USE_METAL) case DXGI_FORMAT_ASTC_4x4_UNORM: case DXGI_FORMAT_ASTC_4x4_UNORM_SRGB: return DXGI_FORMAT_ASTC_4x4_TYPELESS; case DXGI_FORMAT_ASTC_5x4_UNORM: case DXGI_FORMAT_ASTC_5x4_UNORM_SRGB: return DXGI_FORMAT_ASTC_5x4_TYPELESS; case DXGI_FORMAT_ASTC_5x5_UNORM: case DXGI_FORMAT_ASTC_5x5_UNORM_SRGB: return DXGI_FORMAT_ASTC_5x5_TYPELESS; case DXGI_FORMAT_ASTC_6x5_UNORM: case DXGI_FORMAT_ASTC_6x5_UNORM_SRGB: return DXGI_FORMAT_ASTC_6x5_TYPELESS; case DXGI_FORMAT_ASTC_6x6_UNORM: case DXGI_FORMAT_ASTC_6x6_UNORM_SRGB: return DXGI_FORMAT_ASTC_6x6_TYPELESS; case DXGI_FORMAT_ASTC_8x5_UNORM: case DXGI_FORMAT_ASTC_8x5_UNORM_SRGB: return DXGI_FORMAT_ASTC_8x5_TYPELESS; case DXGI_FORMAT_ASTC_8x6_UNORM: case DXGI_FORMAT_ASTC_8x6_UNORM_SRGB: return DXGI_FORMAT_ASTC_8x6_TYPELESS; case DXGI_FORMAT_ASTC_8x8_UNORM: case DXGI_FORMAT_ASTC_8x8_UNORM_SRGB: return DXGI_FORMAT_ASTC_8x8_TYPELESS; case DXGI_FORMAT_ASTC_10x5_UNORM: case DXGI_FORMAT_ASTC_10x5_UNORM_SRGB: return DXGI_FORMAT_ASTC_10x5_TYPELESS; case DXGI_FORMAT_ASTC_10x6_UNORM: case DXGI_FORMAT_ASTC_10x6_UNORM_SRGB: return DXGI_FORMAT_ASTC_10x6_TYPELESS; case DXGI_FORMAT_ASTC_10x8_UNORM: case DXGI_FORMAT_ASTC_10x8_UNORM_SRGB: return DXGI_FORMAT_ASTC_10x8_TYPELESS; case DXGI_FORMAT_ASTC_10x10_UNORM: case DXGI_FORMAT_ASTC_10x10_UNORM_SRGB: return DXGI_FORMAT_ASTC_10x10_TYPELESS; case DXGI_FORMAT_ASTC_12x10_UNORM: case DXGI_FORMAT_ASTC_12x10_UNORM_SRGB: return DXGI_FORMAT_ASTC_12x10_TYPELESS; case DXGI_FORMAT_ASTC_12x12_UNORM: case DXGI_FORMAT_ASTC_12x12_UNORM_SRGB: return DXGI_FORMAT_ASTC_12x12_TYPELESS; #endif // No conversion on floating point format. case DXGI_FORMAT_R11G11B10_FLOAT: return DXGI_FORMAT_R11G11B10_FLOAT; default: assert(0); } return fmt; } bool CTexture::IsFormatSupported(ETEX_Format eTFDst) { const SPixFormatSupport* rd = &gcpRendD3D->m_hwTexFormatSupport; int D3DFmt = DeviceFormatFromTexFormat(eTFDst); if (!D3DFmt) { return false; } SPixFormat* pFmt; for (pFmt = rd->m_FirstPixelFormat; pFmt; pFmt = pFmt->Next) { if (pFmt->DeviceFormat == D3DFmt && pFmt->IsValid()) { return true; } } return false; } ETEX_Format CTexture::ClosestFormatSupported(ETEX_Format eTFDst) { return ClosestFormatSupported(eTFDst, m_pPixelFormat); } ETEX_Format CTexture::ClosestFormatSupported(ETEX_Format eTFDst, const SPixFormat*& pPF) { const SPixFormatSupport* rd = &gcpRendD3D->m_hwTexFormatSupport; switch (eTFDst) { case eTF_R8G8B8A8S: if (rd->m_FormatR8G8B8A8S.IsValid()) { pPF = &rd->m_FormatR8G8B8A8S; return eTF_R8G8B8A8S; } return eTF_Unknown; case eTF_R8G8B8A8: if (rd->m_FormatR8G8B8A8.IsValid()) { pPF = &rd->m_FormatR8G8B8A8; return eTF_R8G8B8A8; } return eTF_Unknown; case eTF_B5G5R5: if (rd->m_FormatB5G5R5.IsValid()) { pPF = &rd->m_FormatB5G5R5; return eTF_B5G5R5; } case eTF_B5G6R5: if (rd->m_FormatB5G6R5.IsValid()) { pPF = &rd->m_FormatB5G6R5; return eTF_B5G6R5; } case eTF_B8G8R8X8: if (rd->m_FormatB8G8R8X8.IsValid()) { pPF = &rd->m_FormatB8G8R8X8; return eTF_B8G8R8X8; } return eTF_Unknown; case eTF_B4G4R4A4: if (rd->m_FormatB4G4R4A4.IsValid()) { pPF = &rd->m_FormatB4G4R4A4; return eTF_B4G4R4A4; } case eTF_B8G8R8A8: if (rd->m_FormatB8G8R8A8.IsValid()) { pPF = &rd->m_FormatB8G8R8A8; return eTF_B8G8R8A8; } return eTF_Unknown; case eTF_A8: if (rd->m_FormatA8.IsValid()) { pPF = &rd->m_FormatA8; return eTF_A8; } return eTF_Unknown; case eTF_R8: if (rd->m_FormatR8.IsValid()) { pPF = &rd->m_FormatR8; return eTF_R8; } return eTF_Unknown; case eTF_R8S: if (rd->m_FormatR8S.IsValid()) { pPF = &rd->m_FormatR8S; return eTF_R8S; } return eTF_Unknown; case eTF_R16: if (rd->m_FormatR16.IsValid()) { pPF = &rd->m_FormatR16; return eTF_R16; } if (rd->m_FormatR16G16.IsValid()) { pPF = &rd->m_FormatR16G16; return eTF_R16G16; } return eTF_Unknown; case eTF_R16U: if (rd->m_FormatR16U.IsValid()) { pPF = &rd->m_FormatR16U; return eTF_R16U; } return eTF_Unknown; case eTF_R16G16U: if (rd->m_FormatR16G16U.IsValid()) { pPF = &rd->m_FormatR16G16U; return eTF_R16G16U; } return eTF_Unknown; case eTF_R10G10B10A2UI: if (rd->m_FormatR10G10B10A2UI.IsValid()) { pPF = &rd->m_FormatR10G10B10A2UI; return eTF_R10G10B10A2UI; } return eTF_Unknown; case eTF_R16F: if (rd->m_FormatR16F.IsValid()) { pPF = &rd->m_FormatR16F; return eTF_R16F; } if (rd->m_FormatR16G16F.IsValid()) { pPF = &rd->m_FormatR16G16F; return eTF_R16G16F; } return eTF_Unknown; case eTF_R32F: if (rd->m_FormatR32F.IsValid()) { pPF = &rd->m_FormatR32F; return eTF_R32F; } if (rd->m_FormatR16G16F.IsValid()) { pPF = &rd->m_FormatR16G16F; return eTF_R16G16F; } return eTF_Unknown; case eTF_R8G8: if (rd->m_FormatR8G8.IsValid()) { pPF = &rd->m_FormatR8G8; return eTF_R8G8; } return eTF_Unknown; case eTF_R8G8S: if (rd->m_FormatR8G8S.IsValid()) { pPF = &rd->m_FormatR8G8S; return eTF_R8G8S; } return eTF_Unknown; case eTF_R16G16: if (rd->m_FormatR16G16.IsValid()) { pPF = &rd->m_FormatR16G16; return eTF_R16G16; } return eTF_Unknown; case eTF_R16G16S: if (rd->m_FormatR16G16S.IsValid()) { pPF = &rd->m_FormatR16G16S; return eTF_R16G16S; } return eTF_Unknown; case eTF_R16G16F: if (rd->m_FormatR16G16F.IsValid()) { pPF = &rd->m_FormatR16G16F; return eTF_R16G16F; } return eTF_Unknown; case eTF_R11G11B10F: if (rd->m_FormatR11G11B10F.IsValid()) { pPF = &rd->m_FormatR11G11B10F; return eTF_R11G11B10F; } return eTF_Unknown; case eTF_R10G10B10A2: if (rd->m_FormatR10G10B10A2.IsValid()) { pPF = &rd->m_FormatR10G10B10A2; return eTF_R10G10B10A2; } return eTF_Unknown; case eTF_R16G16B16A16: if (rd->m_FormatR16G16B16A16.IsValid()) { pPF = &rd->m_FormatR16G16B16A16; return eTF_R16G16B16A16; } return eTF_Unknown; case eTF_R16G16B16A16S: if (rd->m_FormatR16G16B16A16S.IsValid()) { pPF = &rd->m_FormatR16G16B16A16S; return eTF_R16G16B16A16S; } return eTF_Unknown; case eTF_R16G16B16A16F: if (rd->m_FormatR16G16B16A16F.IsValid()) { pPF = &rd->m_FormatR16G16B16A16F; return eTF_R16G16B16A16F; } return eTF_Unknown; case eTF_R32G32B32A32F: if (rd->m_FormatR32G32B32A32F.IsValid()) { pPF = &rd->m_FormatR32G32B32A32F; return eTF_R32G32B32A32F; } return eTF_Unknown; case eTF_BC1: if (rd->m_FormatBC1.IsValid()) { pPF = &rd->m_FormatBC1; return eTF_BC1; } if (rd->m_FormatR8G8B8A8.IsValid()) { pPF = &rd->m_FormatR8G8B8A8; return eTF_R8G8B8A8; } return eTF_Unknown; case eTF_BC2: if (rd->m_FormatBC2.IsValid()) { pPF = &rd->m_FormatBC2; return eTF_BC2; } if (rd->m_FormatR8G8B8A8.IsValid()) { pPF = &rd->m_FormatR8G8B8A8; return eTF_R8G8B8A8; } return eTF_Unknown; case eTF_BC3: if (rd->m_FormatBC3.IsValid()) { pPF = &rd->m_FormatBC3; return eTF_BC3; } if (rd->m_FormatR8G8B8A8.IsValid()) { pPF = &rd->m_FormatR8G8B8A8; return eTF_R8G8B8A8; } return eTF_Unknown; case eTF_BC4U: if (rd->m_FormatBC4U.IsValid()) { pPF = &rd->m_FormatBC4U; return eTF_BC4U; } if (rd->m_FormatR8.IsValid()) { pPF = &rd->m_FormatR8; return eTF_R8; } return eTF_Unknown; case eTF_BC4S: if (rd->m_FormatBC4S.IsValid()) { pPF = &rd->m_FormatBC4S; return eTF_BC4S; } if (rd->m_FormatR8S.IsValid()) { pPF = &rd->m_FormatR8S; return eTF_R8S; } return eTF_Unknown; case eTF_BC5U: if (rd->m_FormatBC5U.IsValid()) { pPF = &rd->m_FormatBC5U; return eTF_BC5U; } if (rd->m_FormatR8G8.IsValid()) { pPF = &rd->m_FormatR8G8; return eTF_R8G8; } return eTF_Unknown; case eTF_BC5S: if (rd->m_FormatBC5S.IsValid()) { pPF = &rd->m_FormatBC5S; return eTF_BC5S; } if (rd->m_FormatR8G8S.IsValid()) { pPF = &rd->m_FormatR8G8S; return eTF_R8G8S; } return eTF_Unknown; case eTF_BC6UH: if (rd->m_FormatBC6UH.IsValid()) { pPF = &rd->m_FormatBC6UH; return eTF_BC6UH; } if (rd->m_FormatR16F.IsValid()) { pPF = &rd->m_FormatR16F; return eTF_R16F; } return eTF_Unknown; case eTF_BC6SH: if (rd->m_FormatBC6SH.IsValid()) { pPF = &rd->m_FormatBC6SH; return eTF_BC6SH; } if (rd->m_FormatR16F.IsValid()) { pPF = &rd->m_FormatR16F; return eTF_R16F; } return eTF_Unknown; case eTF_BC7: if (rd->m_FormatBC7.IsValid()) { pPF = &rd->m_FormatBC7; return eTF_BC7; } if (rd->m_FormatR8G8B8A8.IsValid()) { pPF = &rd->m_FormatR8G8B8A8; return eTF_R8G8B8A8; } return eTF_Unknown; case eTF_R9G9B9E5: if (rd->m_FormatR9G9B9E5.IsValid()) { pPF = &rd->m_FormatR9G9B9E5; return eTF_R9G9B9E5; } if (rd->m_FormatR16G16B16A16F.IsValid()) { pPF = &rd->m_FormatR16G16B16A16F; return eTF_R16G16B16A16F; } return eTF_Unknown; case eTF_D16: if (rd->m_FormatD16.IsValid()) { pPF = &rd->m_FormatD16; return eTF_D16; } case eTF_D24S8: if (rd->m_FormatD24S8.IsValid()) { pPF = &rd->m_FormatD24S8; return eTF_D24S8; } case eTF_D32F: if (rd->m_FormatD32F.IsValid()) { pPF = &rd->m_FormatD32F; return eTF_D32F; } case eTF_D32FS8: if (rd->m_FormatD32FS8.IsValid()) { pPF = &rd->m_FormatD32FS8; return eTF_D32FS8; } return eTF_Unknown; case eTF_EAC_R11: if (rd->m_FormatEAC_R11.IsValid()) { pPF = &rd->m_FormatEAC_R11; return eTF_EAC_R11; } return eTF_Unknown; case eTF_EAC_RG11: if (rd->m_FormatEAC_RG11.IsValid()) { pPF = &rd->m_FormatEAC_RG11; return eTF_EAC_RG11; } return eTF_Unknown; case eTF_ETC2: if (rd->m_FormatETC2.IsValid()) { pPF = &rd->m_FormatETC2; return eTF_ETC2; } return eTF_Unknown; case eTF_ETC2A: if (rd->m_FormatETC2A.IsValid()) { pPF = &rd->m_FormatETC2A; return eTF_ETC2A; } return eTF_Unknown; #ifdef CRY_USE_METAL case eTF_PVRTC2: if (rd->m_FormatPVRTC2.IsValid()) { pPF = &rd->m_FormatPVRTC2; return eTF_PVRTC2; } return eTF_Unknown; case eTF_PVRTC4: if (rd->m_FormatPVRTC4.IsValid()) { pPF = &rd->m_FormatPVRTC4; return eTF_PVRTC4; } return eTF_Unknown; #endif #if defined(ANDROID) || defined(CRY_USE_METAL) case eTF_ASTC_4x4: if (rd->m_FormatASTC_4x4.IsValid()) { pPF = &rd->m_FormatASTC_4x4; return eTF_ASTC_4x4; } return eTF_Unknown; case eTF_ASTC_5x4: if (rd->m_FormatASTC_5x4.IsValid()) { pPF = &rd->m_FormatASTC_5x4; return eTF_ASTC_5x4; } return eTF_Unknown; case eTF_ASTC_5x5: if (rd->m_FormatASTC_5x5.IsValid()) { pPF = &rd->m_FormatASTC_5x5; return eTF_ASTC_5x5; } return eTF_Unknown; case eTF_ASTC_6x5: if (rd->m_FormatASTC_6x5.IsValid()) { pPF = &rd->m_FormatASTC_6x5; return eTF_ASTC_6x5; } return eTF_Unknown; case eTF_ASTC_6x6: if (rd->m_FormatASTC_6x6.IsValid()) { pPF = &rd->m_FormatASTC_6x6; return eTF_ASTC_6x6; } return eTF_Unknown; case eTF_ASTC_8x5: if (rd->m_FormatASTC_8x5.IsValid()) { pPF = &rd->m_FormatASTC_8x5; return eTF_ASTC_8x5; } return eTF_Unknown; case eTF_ASTC_8x6: if (rd->m_FormatASTC_8x6.IsValid()) { pPF = &rd->m_FormatASTC_8x6; return eTF_ASTC_8x6; } return eTF_Unknown; case eTF_ASTC_8x8: if (rd->m_FormatASTC_8x8.IsValid()) { pPF = &rd->m_FormatASTC_8x8; return eTF_ASTC_8x8; } return eTF_Unknown; case eTF_ASTC_10x5: if (rd->m_FormatASTC_10x5.IsValid()) { pPF = &rd->m_FormatASTC_10x5; return eTF_ASTC_10x5; } return eTF_Unknown; case eTF_ASTC_10x6: if (rd->m_FormatASTC_10x6.IsValid()) { pPF = &rd->m_FormatASTC_10x6; return eTF_ASTC_10x6; } return eTF_Unknown; case eTF_ASTC_10x8: if (rd->m_FormatASTC_10x8.IsValid()) { pPF = &rd->m_FormatASTC_10x8; return eTF_ASTC_10x8; } return eTF_Unknown; case eTF_ASTC_10x10: if (rd->m_FormatASTC_10x10.IsValid()) { pPF = &rd->m_FormatASTC_10x10; return eTF_ASTC_10x10; } return eTF_Unknown; case eTF_ASTC_12x10: if (rd->m_FormatASTC_12x10.IsValid()) { pPF = &rd->m_FormatASTC_12x10; return eTF_ASTC_12x10; } return eTF_Unknown; case eTF_ASTC_12x12: if (rd->m_FormatASTC_12x12.IsValid()) { pPF = &rd->m_FormatASTC_12x12; return eTF_ASTC_12x12; } return eTF_Unknown; #endif default: assert(0); } return eTF_Unknown; } //=============================================================================== bool CTexture::CreateRenderTarget(ETEX_Format eTF, const ColorF& cClear) { if (eTF == eTF_Unknown) { eTF = m_eTFDst; } if (eTF == eTF_Unknown) { return false; } const byte* pData[6] = { NULL }; ETEX_Format eTFDst = ClosestFormatSupported(eTF); if (eTF != eTFDst) { return false; } m_eTFDst = eTF; m_nFlags |= FT_USAGE_RENDERTARGET; m_cClearColor = cClear; bool bRes = CreateDeviceTexture(pData); PostCreate(); // Assign name to RT for enhanced debugging #if !defined(_RELEASE) #if defined(WIN32) #define D3DTEXTURE_CPP_USE_PRIVATEDATA #elif defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_3 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif #endif #if defined(D3DTEXTURE_CPP_USE_PRIVATEDATA) if (bRes) { m_pDevTexture->GetBaseTexture()->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(m_SrcName.c_str()), m_SrcName.c_str()); } #endif return bRes; } // Resolve anti-aliased RT to the texture bool CTexture::Resolve(int nTarget, bool bUseViewportSize) { if (m_bResolved) { return true; } m_bResolved = true; if (!(m_nFlags & FT_USAGE_MSAA)) { return true; } assert ((m_nFlags & FT_USAGE_RENDERTARGET) && (m_nFlags & FT_USAGE_MSAA) && m_pDeviceShaderResource && m_pDevTexture && m_pRenderTargetData->m_pDeviceTextureMSAA); CDeviceTexture* pDestSurf = GetDevTexture(); CDeviceTexture* pSrcSurf = GetDevTextureMSAA(); assert(pSrcSurf != NULL); assert(pDestSurf != NULL); gcpRendD3D->GetDeviceContext().ResolveSubresource(pDestSurf->Get2DTexture(), 0, pSrcSurf->Get2DTexture(), 0, (DXGI_FORMAT)m_pPixelFormat->DeviceFormat); return true; } bool CTexture::CreateDeviceTexture(const byte* pData[6]) { if (!m_pPixelFormat) { ETEX_Format eTF = ClosestFormatSupported(m_eTFDst); assert(eTF != eTF_Unknown); assert(eTF == m_eTFDst); } assert(m_pPixelFormat); if (!m_pPixelFormat) { return false; } if (gRenDev->m_pRT->RC_CreateDeviceTexture(this, pData)) { // Assign name to Texture for enhanced debugging #if !defined(RELEASE) #if defined (WIN64) m_pDevTexture->GetBaseTexture()->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(m_SrcName.c_str()), m_SrcName.c_str()); #elif defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_4 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif #endif return true; } return false; } void CTexture::Unbind() { if (m_pDeviceShaderResource) { gcpRendD3D->m_DevMan.UnbindSRV(m_pDeviceShaderResource); } CDeviceTexture* pDevTex = m_pDevTexture; if (pDevTex) { pDevTex->Unbind(); } } bool CTexture::RT_CreateDeviceTexture(const byte* pData[6]) { SCOPED_RENDERER_ALLOCATION_NAME_HINT(GetSourceName()); AZ_ASSET_ATTACH_TO_SCOPE(this); HRESULT hr; int32 nESRAMOffset = -1; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_5 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif //if we have any device owned resources allocated, we must sync with render thread if (m_pDevTexture) { ReleaseDeviceTexture(false); } else { SAFE_DELETE(m_pRenderTargetData); } CD3D9Renderer* r = gcpRendD3D; int nWdt = m_nWidth; int nHgt = m_nHeight; int nDepth = m_nDepth; int nMips = m_nMips; AZ_Assert(nWdt > 0 && nHgt > 0 && nMips > 0, "Attempting to create a device texture '%s' with height:%d, width:%d, and mip levels:%d. All three must be > 0", GetSourceName(), nHgt, nWdt, nMips); #ifdef CRY_USE_METAL bool isMetalCompressedTextureFormat = GetBlockDim(m_eTFSrc) != Vec2i(1); #else bool isMetalCompressedTextureFormat = false; #endif bool allowReinterpretingColorSpace = !isMetalCompressedTextureFormat && RenderCapabilities::SupportsTextureViews(); byte* pTemp = NULL; CDeviceManager* pDevMan = &r->m_DevMan; bool resetSRGB = true; if (m_nFlags & (FT_USAGE_RENDERTARGET | FT_USAGE_UNORDERED_ACCESS)) { m_pRenderTargetData = new RenderTargetData(); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_6 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif } uint32 nArraySize = m_nArraySize; if (m_eTT == eTT_2D) { STextureInfo TI; D3DFormat D3DFmt = m_pPixelFormat->DeviceFormat; //nMips = 1; DXGI_FORMAT nFormatOrig = D3DFmt; resetSRGB = false; m_bIsSRGB &= m_pPixelFormat->bCanReadSRGB && (m_nFlags & (FT_USAGE_MSAA | FT_USAGE_RENDERTARGET)) == 0; if (m_bIsSRGB) { D3DFmt = ConvertToSRGBFmt(D3DFmt); } // must use typeless format to allow runtime casting if (m_nFlags & FT_USAGE_ALLOWREADSRGB && allowReinterpretingColorSpace) { D3DFmt = ConvertToTypelessFmt(D3DFmt); } uint32 nUsage = 0; if (m_nFlags & FT_USAGE_DEPTHSTENCIL) { nUsage |= CDeviceManager::USAGE_DEPTH_STENCIL; } if (m_nFlags & FT_USAGE_RENDERTARGET) { nUsage |= CDeviceManager::USAGE_RENDER_TARGET; } #if defined(AZ_PLATFORM_IOS) if (m_nFlags & FT_USAGE_MEMORYLESS) { nUsage |= CDeviceManager::USAGE_MEMORYLESS; } #endif if (m_nFlags & FT_USAGE_DYNAMIC) { nUsage |= CDeviceManager::USAGE_DYNAMIC; } if (m_nFlags & FT_STAGE_READBACK) { nUsage |= CDeviceManager::USAGE_STAGE_ACCESS | CDeviceManager::USAGE_CPU_READ; } if (m_nFlags & FT_STAGE_UPLOAD) { nUsage |= CDeviceManager::USAGE_STAGE_ACCESS | CDeviceManager::USAGE_CPU_WRITE; } if (m_nFlags & FT_USAGE_UNORDERED_ACCESS #if defined(SUPPORT_DEVICE_INFO) && r->DevInfo().FeatureLevel() >= D3D_FEATURE_LEVEL_11_0 #endif //defined(SUPPORT_DEVICE_INFO) ) { nUsage |= CDeviceManager::USAGE_UNORDERED_ACCESS; } if ((m_nFlags & (FT_DONT_RELEASE | FT_DONT_STREAM)) == (FT_DONT_RELEASE | FT_DONT_STREAM)) { nUsage |= CDeviceManager::USAGE_ETERNAL; } if (m_nFlags & FT_USAGE_UAV_RWTEXTURE) { nUsage |= CDeviceManager::USAGE_UAV_RWTEXTURE; } if (m_nFlags & FT_FORCE_MIPS) { nUsage |= CDeviceManager::USAGE_AUTOGENMIPS; if (nMips <= 1) { m_nMips = nMips = max(1, CTexture::CalcNumMips(nWdt, nHgt) - 2); } } if (m_nFlags & FT_USAGE_MSAA) { m_pRenderTargetData->m_nMSAASamples = (uint8)r->m_RP.m_MSAAData.Type; m_pRenderTargetData->m_nMSAAQuality = (uint8)r->m_RP.m_MSAAData.Quality; TI.m_nMSAASamples = m_pRenderTargetData->m_nMSAASamples; TI.m_nMSAAQuality = m_pRenderTargetData->m_nMSAAQuality; hr = pDevMan->Create2DTexture(m_SrcName, nWdt, nHgt, nMips, nArraySize, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pRenderTargetData->m_pDeviceTextureMSAA, &TI); AZ_Assert(SUCCEEDED(hr), "Call to Create2DTexture failed for '%s'.", GetSourceName()); m_bResolved = false; TI.m_nMSAASamples = 1; TI.m_nMSAAQuality = 0; } if (pData[0]) { { STextureInfoData InitData[20]; int w = nWdt; int h = nHgt; int nOffset = 0; const byte* src = pData[0]; for (int i = 0; i < nMips; i++) { if (!w && !h) { break; } if (!w) { w = 1; } if (!h) { h = 1; } int nSize = TextureDataSize(w, h, 1, 1, 1, m_eTFSrc, m_eSrcTileMode); InitData[i].pSysMem = &src[nOffset]; if (m_eSrcTileMode == eTM_None) { const Vec2i BlockDim = GetBlockDim(m_eTFSrc); if (BlockDim == Vec2i(1)) { InitData[i].SysMemPitch = TextureDataSize(w, 1, 1, 1, 1, m_eTFSrc, eTM_None); } else { int blockSize = CImageExtensionHelper::BytesPerBlock(m_eTFSrc); InitData[i].SysMemPitch = (w + BlockDim.x - 1) / BlockDim.x * blockSize; } //ignored InitData[i].SysMemSlicePitch = nSize; InitData[i].SysMemTileMode = eTM_None; } else { InitData[i].SysMemPitch = 0; InitData[i].SysMemSlicePitch = 0; InitData[i].SysMemTileMode = m_eSrcTileMode; } w >>= 1; h >>= 1; nOffset += nSize; } TI.m_pData = InitData; SAFE_RELEASE(m_pDevTexture); hr = pDevMan->Create2DTexture(m_SrcName, nWdt, nHgt, nMips, nArraySize, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pDevTexture, &TI); if (!FAILED(hr) && m_pDevTexture) { m_pDevTexture->SetNoDelete(!!(m_nFlags & FT_DONT_RELEASE)); } } } else // no texture data so just make an empty texture { #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_7 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif SAFE_RELEASE(m_pDevTexture); hr = pDevMan->Create2DTexture(m_SrcName, nWdt, nHgt, nMips, nArraySize, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pDevTexture, &TI, false, nESRAMOffset); if (!FAILED(hr) && m_pDevTexture) { m_pDevTexture->SetNoDelete(!!(m_nFlags & FT_DONT_RELEASE)); } } if (FAILED(hr)) { AZ_Assert(0, "Call to Create2DTexture failed for '%s'.", GetSourceName()); return false; } // Restore format if (m_nFlags & FT_USAGE_ALLOWREADSRGB) { D3DFmt = nFormatOrig; } ////////////////////////////////////////////////////////////////////////// m_pDeviceShaderResource = static_cast (CreateDeviceResourceView(SResourceView::ShaderResourceView(m_eTFDst, 0, -1, 0, nMips, m_bIsSRGB, false))); m_nMinMipVidActive = 0; if (m_nFlags & FT_USAGE_ALLOWREADSRGB && allowReinterpretingColorSpace) { m_pDeviceShaderResourceSRGB = static_cast (CreateDeviceResourceView(SResourceView::ShaderResourceView(m_eTFDst, 0, -1, 0, nMips, true, false))); } } else if (m_eTT == eTT_Cube) { STextureInfo TI; D3DFormat D3DFmt = m_pPixelFormat->DeviceFormat; uint32 nUsage = 0; if (m_nFlags & FT_USAGE_DEPTHSTENCIL) { nUsage |= CDeviceManager::USAGE_DEPTH_STENCIL; } if (m_nFlags & FT_USAGE_RENDERTARGET) { nUsage |= CDeviceManager::USAGE_RENDER_TARGET; } #if defined(AZ_PLATFORM_IOS) if (m_nFlags & FT_USAGE_MEMORYLESS) { nUsage |= CDeviceManager::USAGE_MEMORYLESS; } #endif if (m_nFlags & FT_USAGE_DYNAMIC) { nUsage |= CDeviceManager::USAGE_DYNAMIC; } if (m_nFlags & FT_STAGE_READBACK) { nUsage |= CDeviceManager::USAGE_STAGE_ACCESS | CDeviceManager::USAGE_CPU_READ; } if (m_nFlags & FT_STAGE_UPLOAD) { nUsage |= CDeviceManager::USAGE_STAGE_ACCESS | CDeviceManager::USAGE_CPU_WRITE; } if ((m_nFlags & (FT_DONT_RELEASE | FT_DONT_STREAM)) == (FT_DONT_RELEASE | FT_DONT_STREAM)) { nUsage |= CDeviceManager::USAGE_ETERNAL; } if (m_nFlags & FT_FORCE_MIPS) { nUsage |= CDeviceManager::USAGE_AUTOGENMIPS; if (nMips <= 1) { m_nMips = nMips = max(1, CTexture::CalcNumMips(nWdt, nHgt) - 2); } } if (m_nFlags & FT_USAGE_MSAA) { m_pRenderTargetData->m_nMSAASamples = (uint8)r->m_RP.m_MSAAData.Type; m_pRenderTargetData->m_nMSAAQuality = (uint8)r->m_RP.m_MSAAData.Quality; TI.m_nMSAASamples = m_pRenderTargetData->m_nMSAASamples; TI.m_nMSAAQuality = m_pRenderTargetData->m_nMSAAQuality; hr = pDevMan->CreateCubeTexture(m_SrcName, nWdt, nMips, m_nArraySize, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pRenderTargetData->m_pDeviceTextureMSAA, &TI); AZ_Assert(SUCCEEDED(hr), "Call to CreateCubeTexuture failed for '%s'.", GetSourceName()); m_bResolved = false; TI.m_nMSAASamples = 1; TI.m_nMSAAQuality = 0; } DXGI_FORMAT nFormatOrig = D3DFmt; DXGI_FORMAT nFormatSRGB = D3DFmt; resetSRGB = false; { m_bIsSRGB &= m_pPixelFormat->bCanReadSRGB && (m_nFlags & (FT_USAGE_MSAA | FT_USAGE_RENDERTARGET)) == 0; if ((m_bIsSRGB || m_nFlags & FT_USAGE_ALLOWREADSRGB)) { nFormatSRGB = ConvertToSRGBFmt(D3DFmt); } if (m_bIsSRGB) { D3DFmt = nFormatSRGB; } // must use typeless format to allow runtime casting if (m_nFlags & FT_USAGE_ALLOWREADSRGB) { D3DFmt = ConvertToTypelessFmt(D3DFmt); } } if (pData[0]) { AZ_Assert(m_nArraySize == 1, "There is no implementation for tex array data."); STextureInfoData InitData[g_nD3D10MaxSupportedSubres]; for (int nSide = 0; nSide < 6; nSide++) { int w = nWdt; int h = nHgt; int nOffset = 0; const byte* src = (!(m_nFlags & FT_REPLICATE_TO_ALL_SIDES)) ? pData[nSide] : pData[0]; for (int i = 0; i < nMips; i++) { if (!w && !h) { break; } if (!w) { w = 1; } if (!h) { h = 1; } int nSubresInd = nSide * nMips + i; int nSize = TextureDataSize(w, h, 1, 1, 1, m_eTFSrc, m_eSrcTileMode); InitData[nSubresInd].pSysMem = &src[nOffset]; if (m_eSrcTileMode == eTM_None) { InitData[nSubresInd].SysMemPitch = TextureDataSize(w, 1, 1, 1, 1, m_eTFSrc, eTM_None); //ignored InitData[nSubresInd].SysMemSlicePitch = nSize; InitData[nSubresInd].SysMemTileMode = eTM_None; } else { InitData[nSubresInd].SysMemPitch = 0; InitData[nSubresInd].SysMemSlicePitch = 0; InitData[nSubresInd].SysMemTileMode = m_eSrcTileMode; } w >>= 1; h >>= 1; nOffset += nSize; } } TI.m_pData = InitData; SAFE_RELEASE(m_pDevTexture); hr = pDevMan->CreateCubeTexture(m_SrcName, nWdt, nMips, m_nArraySize, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pDevTexture, &TI); if (!FAILED(hr) && m_pDevTexture) { m_pDevTexture->SetNoDelete(!!(m_nFlags & FT_DONT_RELEASE)); } } else { //hr = gcpRendD3D->GetDevice().CreateTexture2D(&Desc, 0, 0); // validates parameters //assert(hr == S_FALSE); SAFE_RELEASE(m_pDevTexture); hr = pDevMan->CreateCubeTexture(m_SrcName, nWdt, nMips, m_nArraySize, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pDevTexture, &TI); if (!FAILED(hr) && m_pDevTexture) { m_pDevTexture->SetNoDelete(!!(m_nFlags & FT_DONT_RELEASE)); } } if (FAILED(hr)) { AZ_Assert(0, "Call to CreateCubeTexture failed for '%s'.", GetSourceName()); return false; } if (m_nFlags & FT_USAGE_ALLOWREADSRGB) { D3DFmt = nFormatOrig; } D3DCubeTexture* pID3DTexture = m_pDevTexture->GetCubeTexture(); D3DShaderResourceView* pRes = NULL; D3D11_SHADER_RESOURCE_VIEW_DESC ResDesc; ZeroStruct(ResDesc); ResDesc.Format = (DXGI_FORMAT)ConvertToShaderResourceFmt(D3DFmt); if (m_nArraySize > 1) { ResDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY; ResDesc.TextureCubeArray.MipLevels = nMips; ResDesc.TextureCubeArray.First2DArrayFace = 0; ResDesc.TextureCubeArray.NumCubes = m_nArraySize; // Create the multi-slice shader resource view hr = gcpRendD3D->GetDevice().CreateShaderResourceView(pID3DTexture, &ResDesc, &pRes); if (FAILED(hr)) { AZ_Assert(0, "Call to CreateShaderResourceView failed for '%s'.", GetSourceName()); return false; } m_pDeviceShaderResource = pRes; m_nMinMipVidActive = 0; } else { ResDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; ResDesc.TextureCube.MipLevels = nMips; ResDesc.TextureCube.MostDetailedMip = 0; hr = gcpRendD3D->GetDevice().CreateShaderResourceView(pID3DTexture, &ResDesc, &pRes); if (FAILED(hr)) { AZ_Assert(0, "Call to CreateShaderResourceView failed for '%s'.", GetSourceName()); return false; } m_pDeviceShaderResource = pRes; m_nMinMipVidActive = 0; if (m_nFlags & FT_USAGE_ALLOWREADSRGB) { ResDesc.Format = (DXGI_FORMAT)ConvertToShaderResourceFmt(nFormatSRGB); D3DShaderResourceView* pSRGBRes = NULL; hr = gcpRendD3D->GetDevice().CreateShaderResourceView(pID3DTexture, &ResDesc, &pSRGBRes); if (FAILED(hr)) { AZ_Assert(0, "Call to CreateShaderResourceView failed for '%s'.", GetSourceName()); return false; } //assign shader resource views m_pDeviceShaderResourceSRGB = pSRGBRes; } } } else if (m_eTT == eTT_3D) { STextureInfo TI; D3DFormat D3DFmt = m_pPixelFormat->DeviceFormat; uint32 nUsage = 0; if (m_nFlags & FT_USAGE_DEPTHSTENCIL) { nUsage |= CDeviceManager::USAGE_DEPTH_STENCIL; } if (m_nFlags & FT_USAGE_RENDERTARGET) { nUsage |= CDeviceManager::USAGE_RENDER_TARGET; } #if defined(AZ_PLATFORM_IOS) if (m_nFlags & FT_USAGE_MEMORYLESS) { nUsage |= CDeviceManager::USAGE_MEMORYLESS; } #endif if (m_nFlags & FT_USAGE_DYNAMIC) { nUsage |= CDeviceManager::USAGE_DYNAMIC; } if ((m_nFlags & (FT_DONT_RELEASE | FT_DONT_STREAM)) == (FT_DONT_RELEASE | FT_DONT_STREAM)) { nUsage |= CDeviceManager::USAGE_ETERNAL; } if (m_nFlags & FT_STAGE_READBACK) { nUsage |= CDeviceManager::USAGE_STAGE_ACCESS | CDeviceManager::USAGE_CPU_READ; } if (m_nFlags & FT_STAGE_UPLOAD) { nUsage |= CDeviceManager::USAGE_STAGE_ACCESS | CDeviceManager::USAGE_CPU_WRITE; } if (m_nFlags & FT_USAGE_UNORDERED_ACCESS #if defined(SUPPORT_DEVICE_INFO) && r->DevInfo().FeatureLevel() >= D3D_FEATURE_LEVEL_11_0 #endif //defined(SUPPORT_DEVICE_INFO) ) { nUsage |= CDeviceManager::USAGE_UNORDERED_ACCESS; } if (m_nFlags & FT_USAGE_UAV_RWTEXTURE) { nUsage |= CDeviceManager::USAGE_UAV_RWTEXTURE; } if (m_nFlags & FT_USAGE_MSAA) { m_pRenderTargetData->m_nMSAASamples = (uint8)r->m_RP.m_MSAAData.Type; m_pRenderTargetData->m_nMSAAQuality = (uint8)r->m_RP.m_MSAAData.Quality; TI.m_nMSAASamples = m_pRenderTargetData->m_nMSAASamples; TI.m_nMSAAQuality = m_pRenderTargetData->m_nMSAAQuality; hr = pDevMan->CreateVolumeTexture(m_SrcName, nWdt, nHgt, m_nDepth, nMips, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pRenderTargetData->m_pDeviceTextureMSAA, &TI); AZ_Assert(SUCCEEDED(hr), "Call to CreateVolumeTexture failed for '%s'.", GetSourceName()); m_bResolved = false; TI.m_nMSAASamples = 1; TI.m_nMSAAQuality = 0; } if (pData[0]) { STextureInfoData InitData[15]; int w = nWdt; int h = nHgt; int d = nDepth; int nOffset = 0; const byte* src = pData[0]; for (int i = 0; i < nMips; i++) { if (!w && !h && !d) { break; } if (!w) { w = 1; } if (!h) { h = 1; } if (!d) { d = 1; } int nSliceSize = TextureDataSize(w, h, 1, 1, 1, m_eTFSrc); int nMipSize = TextureDataSize(w, h, d, 1, 1, m_eTFSrc); InitData[i].pSysMem = &src[nOffset]; InitData[i].SysMemPitch = TextureDataSize(w, 1, 1, 1, 1, m_eTFSrc); //ignored InitData[i].SysMemSlicePitch = nSliceSize; InitData[i].SysMemTileMode = eTM_None; w >>= 1; h >>= 1; d >>= 1; nOffset += nMipSize; } TI.m_pData = InitData; SAFE_RELEASE(m_pDevTexture); hr = pDevMan->CreateVolumeTexture(m_SrcName, nWdt, nHgt, nDepth, nMips, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pDevTexture, &TI); if (!FAILED(hr) && m_pDevTexture) { m_pDevTexture->SetNoDelete(!!(m_nFlags & FT_DONT_RELEASE)); } } else { //hr = gcpRendD3D->GetDevice().CreateTexture2D(&Desc, 0, 0); // validates parameters //assert(hr == S_FALSE); SAFE_RELEASE(m_pDevTexture); hr = pDevMan->CreateVolumeTexture(m_SrcName, nWdt, nHgt, nDepth, nMips, nUsage, m_cClearColor, D3DFmt, (D3DPOOL)0, &m_pDevTexture, &TI); if (!FAILED(hr) && m_pDevTexture) { m_pDevTexture->SetNoDelete(!!(m_nFlags & FT_DONT_RELEASE)); } } if (SUCCEEDED(hr)) { PREFAST_ASSUME(m_pDevTexture); m_pDeviceShaderResource = static_cast (CreateDeviceResourceView(SResourceView::ShaderResourceView(m_eTFDst))); m_nMinMipVidActive = 0; } else { AZ_Assert(0, "Call to CreateVolumeTexture failed for '%s'.", GetSourceName()); return false; } } else { AZ_Assert(0, "Texture type not supported for this function."); return false; } SetTexStates(); AZ_Assert(!IsStreamed(), "IsStreamed must be false."); if (m_pDevTexture) { m_nActualSize = m_nPersistentSize = m_pDevTexture->GetDeviceSize(); if (m_nFlags & (FT_USAGE_DYNAMIC | FT_USAGE_RENDERTARGET)) { CTexture::s_nStatsCurDynamicTexMem += m_nActualSize; } else { CTexture::s_nStatsCurManagedNonStreamedTexMem += m_nActualSize; } } // Notify that resource is dirty InvalidateDeviceResource(eDeviceResourceDirty | eDeviceResourceViewDirty); #if defined(D3DTEXTURE_CPP_USE_PRIVATEDATA) if (m_pDevTexture) { m_pDevTexture->GetBaseTexture()->SetPrivateData(WKPDID_D3DDebugObjectName, m_SrcName.length(), m_SrcName.c_str()); } #endif if (!pData[0]) { return true; } int nOffset = 0; if (resetSRGB) { m_bIsSRGB = false; } SetWasUnload(false); SAFE_DELETE_ARRAY(pTemp); return true; } void CTexture::ReleaseDeviceTexture(bool bKeepLastMips, bool bFromUnload) { PROFILE_FRAME(CTexture_ReleaseDeviceTexture); AZ_TRACE_METHOD(); if (!gcpRendD3D->m_pRT->IsRenderThread()) { if (!gcpRendD3D->m_pRT->IsMainThread()) { CryFatalError("Texture is deleted from non-main and non-render thread, which causes command buffer corruption!"); } // Push to render thread to process gcpRendD3D->m_pRT->RC_ReleaseDeviceTexture(this); return; } Unbind(); if (!bFromUnload) { AbortStreamingTasks(this); } if (s_pTextureStreamer) { s_pTextureStreamer->OnTextureDestroy(this); } SAFE_DELETE(m_pRenderTargetData); if (!m_bNoTexture) { CDeviceTexture* pTex = m_pDevTexture; D3DShaderResourceView* pSRVSRGB = m_pDeviceShaderResourceSRGB; SAFE_RELEASE(pSRVSRGB); m_pDeviceShaderResourceSRGB = NULL; D3DShaderResourceView* pSRV = m_pDeviceShaderResource; SAFE_RELEASE(pSRV); m_pDeviceShaderResource = 0; D3DSurface* pRTV = m_pDeviceRTV; SAFE_RELEASE(pRTV); m_pDeviceRTV = NULL; D3DSurface* pRTVMS = m_pDeviceRTVMS; SAFE_RELEASE(pRTVMS); m_pDeviceRTVMS = NULL; if (!m_pFileTexMips || !m_pFileTexMips->m_pPoolItem) { if (IsStreamed()) { SAFE_DELETE(pTex); // for manually created textures } else { SAFE_RELEASE(pTex); } } m_pDevTexture = NULL; // otherwise it's already taken into account in the m_pFileTexMips->m_pPoolItem's dtor if (!m_pFileTexMips || !m_pFileTexMips->m_pPoolItem) { if (IsDynamic()) { assert(CTexture::s_nStatsCurDynamicTexMem >= m_nActualSize); CTexture::s_nStatsCurDynamicTexMem -= m_nActualSize; } else if (!IsStreamed()) { assert(CTexture::s_nStatsCurManagedNonStreamedTexMem >= m_nActualSize); CTexture::s_nStatsCurManagedNonStreamedTexMem -= m_nActualSize; } } if (m_pFileTexMips) { m_bStreamPrepared = false; StreamRemoveFromPool(); if (bKeepLastMips) { const int nLastMipsStart = m_nMips - m_CacheFileHeader.m_nMipsPersistent; int nSides = StreamGetNumSlices(); for (int nS = 0; nS < nSides; nS++) { for (int i = 0; i < nLastMipsStart; i++) { SMipData* mp = &m_pFileTexMips->m_pMipHeader[i].m_Mips[nS]; mp->Free(); } } } else { Unlink(); StreamState_ReleaseInfo(this, m_pFileTexMips); m_pFileTexMips = NULL; m_bStreamed = false; SetStreamingInProgress(InvalidStreamSlot); m_bStreamRequested = false; } } m_nActualSize = 0; m_nPersistentSize = 0; } else { m_pDevTexture = NULL; m_pDeviceRTV = NULL; m_pDeviceShaderResource = NULL; m_pDeviceShaderResourceSRGB = NULL; } m_bNoTexture = false; } void* CTexture::CreateDeviceResourceView(const SResourceView& rv) { const SPixFormat* pPixFormat = NULL; if (ClosestFormatSupported((ETEX_Format)rv.m_Desc.nFormat, pPixFormat) == eTF_Unknown) { return NULL; } HRESULT hr = E_FAIL; void* pResult = NULL; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_8 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else // DX expects -1 for selecting all mip maps/slices. max count throws an exception const uint nSliceCount = rv.m_Desc.nSliceCount == SResourceView().m_Desc.nSliceCount ? (uint) - 1 : (uint)rv.m_Desc.nSliceCount; #endif if (!m_pDevTexture) { return nullptr; } D3DTexture* pTex = m_pDevTexture->Get2DTexture(); switch (rv.m_Desc.eViewType) { case SResourceView::eShaderResourceView: { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; SetShaderResourceViewDesc(rv, m_eTT, pPixFormat->DeviceFormat, m_nArraySize, nSliceCount, srvDesc); if (rv.m_Desc.bMultisample && m_eTT == eTT_2D) { pTex = m_pRenderTargetData->m_pDeviceTextureMSAA->Get2DTexture(); } D3DShaderResourceView* pSRV = NULL; hr = gcpRendD3D->GetDevice().CreateShaderResourceView(pTex, &srvDesc, &pSRV); pResult = pSRV; #if defined(D3DTEXTURE_CPP_USE_PRIVATEDATA) if (pSRV) { AZStd::string srvName = AZStd::string::format("[SRV] %s", m_SrcName.c_str()); pSRV->SetPrivateData(WKPDID_D3DDebugObjectName, srvName.length(), srvName.c_str()); } #endif } break; case SResourceView::eRenderTargetView: { D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; SetRenderTargetViewDesc(rv, m_eTT, pPixFormat->DeviceFormat, m_nArraySize, nSliceCount, rtvDesc); if (rv.m_Desc.bMultisample && m_eTT == eTT_2D) { pTex = m_pRenderTargetData->m_pDeviceTextureMSAA->Get2DTexture(); } D3DSurface* pRTV = NULL; hr = gcpRendD3D->GetDevice().CreateRenderTargetView(pTex, &rtvDesc, &pRTV); pResult = pRTV; #if defined(D3DTEXTURE_CPP_USE_PRIVATEDATA) if (pRTV) { AZStd::string rtvName = AZStd::string::format("[RTV] %s", m_SrcName.c_str()); pRTV->SetPrivateData(WKPDID_D3DDebugObjectName, rtvName.length(), rtvName.c_str()); } #endif } break; case SResourceView::eDepthStencilView: { D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; SetDepthStencilViewDesc(rv, m_eTT, pPixFormat->DeviceFormat, m_nArraySize, nSliceCount, dsvDesc); dsvDesc.Flags = rv.m_Desc.nFlags; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_9 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif D3DDepthSurface* pDSV = NULL; hr = gcpRendD3D->GetDevice().CreateDepthStencilView(pTex, &dsvDesc, &pDSV); pResult = pDSV; #if defined(D3DTEXTURE_CPP_USE_PRIVATEDATA) if (pDSV) { AZStd::string dsvName = AZStd::string::format("[DSV] %s", m_SrcName.c_str()); pDSV->SetPrivateData(WKPDID_D3DDebugObjectName, dsvName.length(), dsvName.c_str()); } #endif } break; case SResourceView::eUnorderedAccessView: { D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; SetUnorderedAccessViewDesc(rv, m_eTT, pPixFormat->DeviceFormat, m_nArraySize, nSliceCount, uavDesc); if (rv.m_Desc.nFlags & 0x1) // typed UAV loads are only allowed for single-component 32-bit element types { uavDesc.Format = DXGI_FORMAT_R32_UINT; } D3DUnorderedAccessView* pUAV = NULL; hr = gcpRendD3D->GetDevice().CreateUnorderedAccessView(pTex, &uavDesc, &pUAV); pResult = pUAV; #if defined(D3DTEXTURE_CPP_USE_PRIVATEDATA) if (pUAV) { AZStd::string uavName = AZStd::string::format("[UAV] %s", m_SrcName.c_str()); pUAV->SetPrivateData(WKPDID_D3DDebugObjectName, uavName.length(), uavName.c_str()); } #endif } break; } if (FAILED(hr)) { CRY_ASSERT(0); return NULL; } return pResult; } void CTexture::SetTexStates() { STexState s; const bool noMipFiltering = m_nMips <= 1 && !(m_nFlags & FT_FORCE_MIPS); s.m_nMinFilter = FILTER_LINEAR; s.m_nMagFilter = FILTER_LINEAR; s.m_nMipFilter = noMipFiltering ? FILTER_NONE : FILTER_LINEAR; const int addrMode = (m_nFlags & FT_STATE_CLAMP || m_eTT == eTT_Cube) ? TADDR_CLAMP : TADDR_WRAP; s.SetClampMode(addrMode, addrMode, addrMode); m_nDefState = (uint16)CTexture::GetTexState(s); } static uint32 sAddressMode(int nAddress) { IF (nAddress < 0, 0) { nAddress = TADDR_WRAP; } switch (nAddress) { case TADDR_WRAP: return D3D11_TEXTURE_ADDRESS_WRAP; case TADDR_CLAMP: return D3D11_TEXTURE_ADDRESS_CLAMP; case TADDR_BORDER: return D3D11_TEXTURE_ADDRESS_BORDER; case TADDR_MIRROR: return D3D11_TEXTURE_ADDRESS_MIRROR; default: assert(0); return D3D11_TEXTURE_ADDRESS_WRAP; } } void STexState::SetComparisonFilter(bool bEnable) { if (m_pDeviceState) { D3DSamplerState* pSamp = (D3DSamplerState*)m_pDeviceState; SAFE_RELEASE(pSamp); m_pDeviceState = NULL; } m_bComparison = bEnable; } bool STexState::SetClampMode(int nAddressU, int nAddressV, int nAddressW) { if (m_pDeviceState) { D3DSamplerState* pSamp = (D3DSamplerState*)m_pDeviceState; SAFE_RELEASE(pSamp); m_pDeviceState = NULL; } m_nAddressU = sAddressMode(nAddressU); m_nAddressV = sAddressMode(nAddressV); m_nAddressW = sAddressMode(nAddressW); return true; } bool STexState::SetFilterMode(int nFilter) { IF (nFilter < 0, 0) { nFilter = FILTER_TRILINEAR; } if (m_pDeviceState) { D3DSamplerState* pSamp = (D3DSamplerState*)m_pDeviceState; SAFE_RELEASE(pSamp); m_pDeviceState = NULL; } switch (nFilter) { case FILTER_POINT: case FILTER_NONE: m_nMinFilter = FILTER_POINT; m_nMagFilter = FILTER_POINT; m_nMipFilter = FILTER_NONE; m_nAnisotropy = 1; break; case FILTER_LINEAR: m_nMinFilter = FILTER_LINEAR; m_nMagFilter = FILTER_LINEAR; m_nMipFilter = FILTER_NONE; m_nAnisotropy = 1; break; case FILTER_BILINEAR: m_nMinFilter = FILTER_LINEAR; m_nMagFilter = FILTER_LINEAR; m_nMipFilter = FILTER_POINT; m_nAnisotropy = 1; break; case FILTER_TRILINEAR: m_nMinFilter = FILTER_LINEAR; m_nMagFilter = FILTER_LINEAR; m_nMipFilter = FILTER_LINEAR; m_nAnisotropy = 1; break; case FILTER_ANISO2X: case FILTER_ANISO4X: case FILTER_ANISO8X: case FILTER_ANISO16X: m_nMinFilter = nFilter; m_nMagFilter = nFilter; m_nMipFilter = nFilter; if (nFilter == FILTER_ANISO2X) { m_nAnisotropy = min(gcpRendD3D->m_MaxAnisotropyLevel, 2); } else if (nFilter == FILTER_ANISO4X) { m_nAnisotropy = min(gcpRendD3D->m_MaxAnisotropyLevel, 4); } else if (nFilter == FILTER_ANISO8X) { m_nAnisotropy = min(gcpRendD3D->m_MaxAnisotropyLevel, 8); } else if (nFilter == FILTER_ANISO16X) { m_nAnisotropy = min(gcpRendD3D->m_MaxAnisotropyLevel, 16); } break; default: assert(0); return false; } return true; } void STexState::SetBorderColor(DWORD dwColor) { if (m_pDeviceState) { D3DSamplerState* pSamp = (D3DSamplerState*)m_pDeviceState; SAFE_RELEASE(pSamp); m_pDeviceState = NULL; } m_dwBorderColor = dwColor; } void STexState::PostCreate() { if (m_pDeviceState) { return; } D3D11_SAMPLER_DESC Desc; ZeroStruct(Desc); D3DSamplerState* pSamp = NULL; // AddressMode of 0 is INVALIDARG Desc.AddressU = m_nAddressU ? (D3D11_TEXTURE_ADDRESS_MODE)m_nAddressU : D3D11_TEXTURE_ADDRESS_WRAP; Desc.AddressV = m_nAddressV ? (D3D11_TEXTURE_ADDRESS_MODE)m_nAddressV : D3D11_TEXTURE_ADDRESS_WRAP; Desc.AddressW = m_nAddressW ? (D3D11_TEXTURE_ADDRESS_MODE)m_nAddressW : D3D11_TEXTURE_ADDRESS_WRAP; ColorF col((uint32)m_dwBorderColor); Desc.BorderColor[0] = col.r; Desc.BorderColor[1] = col.g; Desc.BorderColor[2] = col.b; Desc.BorderColor[3] = col.a; if (m_bComparison) { Desc.ComparisonFunc = D3D11_COMPARISON_LESS; } else { Desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; } Desc.MaxAnisotropy = 1; Desc.MinLOD = 0; if (m_nMipFilter == FILTER_NONE) { Desc.MaxLOD = 0.0f; } else { Desc.MaxLOD = 100.0f; } Desc.MipLODBias = m_MipBias; if (m_bComparison) { if (m_nMinFilter == FILTER_LINEAR && m_nMagFilter == FILTER_LINEAR && m_nMipFilter == FILTER_LINEAR || m_nMinFilter == FILTER_TRILINEAR || m_nMagFilter == FILTER_TRILINEAR) { Desc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; } else if (m_nMinFilter == FILTER_LINEAR && m_nMagFilter == FILTER_LINEAR && (m_nMipFilter == FILTER_NONE || m_nMipFilter == FILTER_POINT) || m_nMinFilter == FILTER_BILINEAR || m_nMagFilter == FILTER_BILINEAR) { Desc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT; } else if (m_nMinFilter == FILTER_POINT && m_nMagFilter == FILTER_POINT && (m_nMipFilter == FILTER_NONE || m_nMipFilter == FILTER_POINT)) { Desc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT; } else if (m_nMinFilter >= FILTER_ANISO2X && m_nMagFilter >= FILTER_ANISO2X && m_nMipFilter >= FILTER_ANISO2X) { Desc.Filter = D3D11_FILTER_COMPARISON_ANISOTROPIC; Desc.MaxAnisotropy = m_nAnisotropy; } } else { if (m_nMinFilter == FILTER_LINEAR && m_nMagFilter == FILTER_LINEAR && m_nMipFilter == FILTER_LINEAR || m_nMinFilter == FILTER_TRILINEAR || m_nMagFilter == FILTER_TRILINEAR) { Desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; } else if (m_nMinFilter == FILTER_LINEAR && m_nMagFilter == FILTER_LINEAR && (m_nMipFilter == FILTER_NONE || m_nMipFilter == FILTER_POINT) || m_nMinFilter == FILTER_BILINEAR || m_nMagFilter == FILTER_BILINEAR) { Desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; } else if (m_nMinFilter == FILTER_POINT && m_nMagFilter == FILTER_POINT && (m_nMipFilter == FILTER_NONE || m_nMipFilter == FILTER_POINT)) { Desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; } else if (m_nMinFilter >= FILTER_ANISO2X && m_nMagFilter >= FILTER_ANISO2X && m_nMipFilter >= FILTER_ANISO2X) { Desc.Filter = D3D11_FILTER_ANISOTROPIC; Desc.MaxAnisotropy = m_nAnisotropy; } else { assert(0); } } HRESULT hr = gcpRendD3D->GetDevice().CreateSamplerState(&Desc, &pSamp); if (SUCCEEDED(hr)) { m_pDeviceState = pSamp; } else { assert(0); } } void STexState::Destroy() { if (m_pDeviceState) { D3DSamplerState* pSamp = (D3DSamplerState*)m_pDeviceState; SAFE_RELEASE(pSamp); m_pDeviceState = NULL; } } void STexState::Init(const STexState& src) { memcpy(this, &src, sizeof(src)); if (m_pDeviceState) { D3DSamplerState* pSamp = (D3DSamplerState*)m_pDeviceState; pSamp->AddRef(); } } bool CTexture::SetClampingMode(int nAddressU, int nAddressV, int nAddressW) { return s_sDefState.SetClampMode(nAddressU, nAddressV, nAddressW); } bool CTexture::SetFilterMode(int nFilter) { return s_sDefState.SetFilterMode(nFilter); } void CTexture::UpdateTexStates() { m_nDefState = (uint16)CTexture::GetTexState(s_sDefState); } void CTexture::SetSamplerState(int nTS, int nSUnit, EHWShaderClass eHWSC) { FUNCTION_PROFILER_RENDER_FLAT assert(gcpRendD3D->m_pRT->IsRenderThread()); STexStageInfo* const __restrict TexStages = s_TexStages; STexState* pTS = &s_TexStates[nTS]; D3DSamplerState* pSamp = (D3DSamplerState*)pTS->m_pDeviceState; assert(pSamp); if (pSamp) { if (eHWSC == eHWSC_Pixel) { gcpRendD3D->m_DevMan.BindSampler(eHWSC_Pixel, &pSamp, nSUnit, 1); } else if (eHWSC == eHWSC_Domain) { gcpRendD3D->m_DevMan.BindSampler(eHWSC_Domain, &pSamp, nSUnit, 1); } else if (eHWSC == eHWSC_Vertex) { gcpRendD3D->m_DevMan.BindSampler(eHWSC_Vertex, &pSamp, nSUnit, 1); } else if (eHWSC == eHWSC_Compute) { gcpRendD3D->m_DevMan.BindSampler(eHWSC_Compute, &pSamp, nSUnit, 1); } else if (eHWSC == eHWSC_Geometry) { gcpRendD3D->m_DevMan.BindSampler(eHWSC_Geometry, &pSamp, nSUnit, 1); } else { assert(0); } } } void CTexture::ApplySamplerState(int nSUnit, EHWShaderClass eHWSC, int nState) { FUNCTION_PROFILER_RENDER_FLAT uint32 nTSSel = Isel32(nState, (int32)m_nDefState); assert(nTSSel >= 0 && nTSSel < s_TexStates.size()); STexStageInfo *TexStages = s_TexStages; CDeviceTexture* pDevTex = m_pDevTexture; // avoiding L2 cache misses from usage from up ahead PrefetchLine(pDevTex, 0); assert(nSUnit >= 0 && nSUnit < 16); assert((nSUnit >= 0 || nSUnit == -2) && nSUnit < gcpRendD3D->m_NumSamplerSlots); CD3D9Renderer *const __restrict rd = gcpRendD3D; const int nFrameID = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_nFrameUpdateID; if (IsVertexTexture()) eHWSC = eHWSC_Vertex; SetSamplerState(nTSSel, nSUnit, eHWSC); } //------------------------------------------------------------------------------ // Given a texture and a binding slot, this is the method that actually refreshes // the texture resource, validates it and finally binds it to the HW stage. void CTexture::ApplyTexture(int nTUnit, EHWShaderClass eHWSC, SResourceView::KeyType nResViewKey) { FUNCTION_PROFILER_RENDER_FLAT STexStageInfo *TexStages = s_TexStages; CDeviceTexture* pDevTex = m_pDevTexture; // avoiding L2 cache misses from usage from up ahead PrefetchLine(pDevTex, 0); assert(nTUnit >= 0 && nTUnit < gcpRendD3D->m_NumResourceSlots); CD3D9Renderer *const __restrict rd = gcpRendD3D; const int nFrameID = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_nFrameUpdateID; if (IsStreamed() && !m_bPostponed) { bool bIsUnloaded = IsUnloaded(); assert(m_pFileTexMips); if (bIsUnloaded || !m_bStreamPrepared || IsPartiallyLoaded()) { PROFILE_FRAME(Texture_Precache); if (!CRenderer::CV_r_texturesstreaming || !m_bStreamPrepared || bIsUnloaded) { if (bIsUnloaded) StreamLoadFromCache(0); else Load(m_eTFDst); pDevTex = m_pDevTexture; } } } IF(this != CTexture::s_pTexNULL && (!pDevTex || !pDevTex->GetBaseTexture()), 0) { // apply black by default CTexture* pBlackTexture = CTextureManager::Instance()->GetBlackTexture(); if (m_eTT != eTT_Cube && pBlackTexture) { pBlackTexture->ApplyTexture(nTUnit, eHWSC, nResViewKey); } else { pBlackTexture = CTextureManager::Instance()->GetBlackTextureCM(); if (m_eTT == eTT_Cube && pBlackTexture) { pBlackTexture->ApplyTexture(nTUnit, eHWSC, nResViewKey); } } return; } // Resolve multisampled RT to texture if (!m_bResolved) { Resolve(); } bool bStreamed = IsStreamed(); if (m_nAccessFrameID != nFrameID) { m_nAccessFrameID = nFrameID; #if !defined(_RELEASE) rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_NumTextures++; if (m_nFlags & (FT_USAGE_RENDERTARGET | FT_USAGE_DYNAMIC)) { rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_DynTexturesSize += m_nActualSize; } else { if (bStreamed) { rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_ManagedTexturesStreamVidSize += m_nActualSize; rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_ManagedTexturesStreamSysSize += StreamComputeDevDataSize(0); } else { rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_ManagedTexturesSysMemSize += m_nActualSize; rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_ManagedTexturesVidMemSize += m_nActualSize; } } #endif // mip map fade in if (bStreamed) { const float fCurrentMipBias = m_fCurrentMipBias; if (fabsf(fCurrentMipBias) > 0.26667f) { // one mip per half a second m_fCurrentMipBias -= 0.26667f * fCurrentMipBias; gcpRendD3D->GetDeviceContext().SetResourceMinLOD(pDevTex->Get2DTexture(), m_fCurrentMipBias + (float)m_nMinMipVidUploaded); } else if (fCurrentMipBias != 0.f) { m_fCurrentMipBias = 0.f; } } } if (IsVertexTexture()) eHWSC = eHWSC_Vertex; const bool bUnnorderedAcessView = SResourceView(nResViewKey).m_Desc.eViewType == SResourceView::eUnorderedAccessView; D3DShaderResourceView* pResView = GetShaderResourceView(nResViewKey); if (pDevTex == TexStages[nTUnit].m_DevTexture && pResView == TexStages[nTUnit].m_pCurResView && eHWSC == TexStages[nTUnit].m_eHWSC) return; TexStages[nTUnit].m_pCurResView = pResView; TexStages[nTUnit].m_eHWSC = eHWSC; // This must get re-factored post C3. // This check is ultra-buggy, render targets setup is deferred until last moment might not be matching this check at all. Also very wrong for MRTs if (rd->m_pCurTarget[0] == this) { //assert(rd->m_pCurTarget[0]->m_pDeviceRTV); rd->m_pNewTarget[0]->m_bWasSetRT = false; rd->GetDeviceContext().OMSetRenderTargets(1, &rd->m_pNewTarget[0]->m_pTarget, rd->m_pNewTarget[0]->m_pDepth); } TexStages[nTUnit].m_DevTexture = pDevTex; #if !defined(_RELEASE) rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_NumTextChanges++; #endif #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { if (IsNoTexture()) { rd->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "CTexture::Apply(): (%d) \"%s\" (Not found)\n", nTUnit, m_SrcName.c_str()); } else { rd->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "CTexture::Apply(): (%d) \"%s\"\n", nTUnit, m_SrcName.c_str()); } } #endif { #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3 && int64(nResViewKey) >= 0) { rd->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "CTexture::Apply(): Shader Resource View: %ul \n", nResViewKey); } #endif if (bUnnorderedAcessView) { // todo: // - add support for pixel shader side via OMSetRenderTargetsAndUnorderedAccessViews // - DX11.1 very likely API will be similar to CSSetUnorderedAccessViews, but for all stages D3DUnorderedAccessView *pUAV = (D3DUnorderedAccessView*)pResView; rd->GetDeviceContext().CSSetUnorderedAccessViews(nTUnit, 1, &pUAV, NULL); return; } { if (IsVertexTexture()) eHWSC = eHWSC_Vertex; if (eHWSC == eHWSC_Pixel) { rd->m_DevMan.BindSRV(eHWSC_Pixel, pResView, nTUnit); } else if (eHWSC == eHWSC_Vertex) { rd->m_DevMan.BindSRV(eHWSC_Vertex, pResView, nTUnit); } else if (eHWSC == eHWSC_Domain) { rd->m_DevMan.BindSRV(eHWSC_Domain, pResView, nTUnit); } else if (eHWSC == eHWSC_Compute) { rd->m_DevMan.BindSRV(eHWSC_Compute, pResView, nTUnit); } else { assert(0); } } } } void CTexture::Apply(int nTUnit, int nState, int nTexMatSlot, int nSUnit, SResourceView::KeyType nResViewKey, EHWShaderClass eHWSC) { FUNCTION_PROFILER_RENDER_FLAT assert(nTUnit >= 0); uint32 nTSSel = Isel32(nState, (int32)m_nDefState); assert(nTSSel >= 0 && nTSSel < s_TexStates.size()); #if defined(OPENGL) // Due to driver issues on MALI gpus only point filtering is allowed for 32 bit float textures. // If another filtering is used the sampler returns black. if ((gcpRendD3D->m_Features | RFT_HW_ARM_MALI) && (m_eTFDst == eTF_R32F || m_eTFDst == eTF_R32G32B32A32F) && (s_TexStates[nTSSel].m_nMagFilter != FILTER_POINT || s_TexStates[nTSSel].m_nMinFilter != FILTER_POINT)) { STexState newState = s_TexStates[nTSSel]; newState.SetFilterMode(FILTER_POINT); nTSSel = CTexture::GetTexState(newState); AZ_WarningOnce("Texture", false, "The current device only supports point filtering for full float textures. Forcing filtering for texture in slot %d", nTUnit); } #endif // defined(OPENGL) STexStageInfo* TexStages = s_TexStages; CDeviceTexture* pDevTex = m_pDevTexture; // avoiding L2 cache misses from usage from up ahead PrefetchLine(pDevTex, 0); if (nSUnit >= -1) { nSUnit = Isel32(nSUnit, nTUnit); } assert(nTUnit >= 0 && nTUnit < gcpRendD3D->m_NumResourceSlots); assert((nSUnit >= 0 || nSUnit == -2) && nSUnit < gcpRendD3D->m_NumSamplerSlots); CD3D9Renderer* const __restrict rd = gcpRendD3D; const int nFrameID = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_nFrameUpdateID; if (IsStreamed() && !m_bPostponed) { bool bIsUnloaded = IsUnloaded(); assert(m_pFileTexMips); if (bIsUnloaded || !m_bStreamPrepared || IsPartiallyLoaded()) { PROFILE_FRAME(Texture_Precache); if (!CRenderer::CV_r_texturesstreaming || !m_bStreamPrepared || bIsUnloaded) { if (bIsUnloaded) { StreamLoadFromCache(0); } else { Load(m_eTFDst); } pDevTex = m_pDevTexture; } } if (nTexMatSlot != EFTT_UNKNOWN) { m_nStreamingPriority = max((int8)m_nStreamingPriority, TextureHelpers::LookupTexPriority((EEfResTextures)nTexMatSlot)); } } IF (this != CTexture::s_pTexNULL && (!pDevTex || !pDevTex->GetBaseTexture()), 0) { // apply black by default if (m_eTT != eTT_Cube && CTextureManager::Instance()->GetBlackTexture() && this != CTextureManager::Instance()->GetBlackTexture()) { CTextureManager::Instance()->GetBlackTexture()->Apply(nTUnit, nState, nTexMatSlot, nSUnit, nResViewKey); } else if (m_eTT == eTT_Cube && CTextureManager::Instance()->GetBlackTextureCM() && this != CTextureManager::Instance()->GetBlackTextureCM()) { CTextureManager::Instance()->GetBlackTextureCM()->Apply(nTUnit, nState, nTexMatSlot, nSUnit, nResViewKey); } return; } // Resolve multisampled RT to texture if (!m_bResolved) { Resolve(); } bool bStreamed = IsStreamed(); if (m_nAccessFrameID != nFrameID) { m_nAccessFrameID = nFrameID; #if !defined(_RELEASE) rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_NumTextures++; if (m_nFlags & (FT_USAGE_RENDERTARGET | FT_USAGE_DYNAMIC)) { rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_DynTexturesSize += m_nActualSize; } else { if (bStreamed) { rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_ManagedTexturesStreamVidSize += m_nActualSize; rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_ManagedTexturesStreamSysSize += StreamComputeDevDataSize(0); } else { rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_ManagedTexturesSysMemSize += m_nActualSize; rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_ManagedTexturesVidMemSize += m_nActualSize; } } #endif // mip map fade in if (bStreamed) { const float fCurrentMipBias = m_fCurrentMipBias; if (fabsf(fCurrentMipBias) > 0.26667f) { // one mip per half a second m_fCurrentMipBias -= 0.26667f * fCurrentMipBias; #if defined(CRY_USE_METAL) //For metal, the lodminclamp is set once at initialization for the mtlsamplerstate. The mtlSamplerDescriptor's properties //are only used during mtlSamplerState object creation; once created the behaviour of a sampler state object is //fixed and cannot be changed. Hence we modify the descriptor with minlod and recreate the sampler state. STexState* pTS = &s_TexStates[nTSSel]; D3DSamplerState* pSamp = (D3DSamplerState*)pTS->m_pDeviceState; pSamp->SetLodMinClamp(m_fCurrentMipBias + static_cast(m_nMinMipVidUploaded)); #else gcpRendD3D->GetDeviceContext().SetResourceMinLOD(pDevTex->Get2DTexture(), m_fCurrentMipBias + static_cast(m_nMinMipVidUploaded)); #endif } else if (fCurrentMipBias != 0.f) { m_fCurrentMipBias = 0.f; } } } if (IsVertexTexture()) { eHWSC = eHWSC_Vertex; } const bool bUnnorderedAcessView = SResourceView(nResViewKey).m_Desc.eViewType == SResourceView::eUnorderedAccessView; if (!bUnnorderedAcessView && nSUnit >= 0) { SetSamplerState(nTSSel, nSUnit, eHWSC); } D3DShaderResourceView* pResView = GetShaderResourceView(nResViewKey, s_TexStates[nTSSel].m_bSRGBLookup); if (pDevTex == TexStages[nTUnit].m_DevTexture && pResView == TexStages[nTUnit].m_pCurResView && eHWSC == TexStages[nTUnit].m_eHWSC) { return; } TexStages[nTUnit].m_pCurResView = pResView; TexStages[nTUnit].m_eHWSC = eHWSC; // This must get re-factored post C3. // - This check is ultra-buggy, render targets setup is deferred until last moment might not be matching this check at all. Also very wrong for MRTs if (rd->m_pCurTarget[0] == this) { //assert(rd->m_pCurTarget[0]->m_pDeviceRTV); rd->m_pNewTarget[0]->m_bWasSetRT = false; rd->GetDeviceContext().OMSetRenderTargets(1, &rd->m_pNewTarget[0]->m_pTarget, rd->m_pNewTarget[0]->m_pDepth); } TexStages[nTUnit].m_DevTexture = pDevTex; #if !defined(_RELEASE) rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_NumTextChanges++; #endif #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { if (IsNoTexture()) { rd->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "CTexture::Apply(): (%d) \"%s\" (Not found)\n", nTUnit, m_SrcName.c_str()); } else { rd->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "CTexture::Apply(): (%d) \"%s\"\n", nTUnit, m_SrcName.c_str()); } } #endif { #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3 && int64(nResViewKey) >= 0) { rd->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "CTexture::Apply(): Shader Resource View: %ul \n", nResViewKey); } #endif if (bUnnorderedAcessView) { // todo: // - add support for pixel shader side via OMSetRenderTargetsAndUnorderedAccessViews // - DX11.1 very likely API will be similar to CSSetUnorderedAccessViews, but for all stages D3DUnorderedAccessView* pUAV = (D3DUnorderedAccessView*)pResView; rd->GetDeviceContext().CSSetUnorderedAccessViews(nTUnit, 1, &pUAV, NULL); return; } { if (IsVertexTexture()) { eHWSC = eHWSC_Vertex; } if (eHWSC == eHWSC_Pixel) { rd->m_DevMan.BindSRV(eHWSC_Pixel, pResView, nTUnit); } else if (eHWSC == eHWSC_Vertex) { rd->m_DevMan.BindSRV(eHWSC_Vertex, pResView, nTUnit); } else if (eHWSC == eHWSC_Domain) { rd->m_DevMan.BindSRV(eHWSC_Domain, pResView, nTUnit); } else if (eHWSC == eHWSC_Compute) { rd->m_DevMan.BindSRV(eHWSC_Compute, pResView, nTUnit); } else if (eHWSC == eHWSC_Geometry) { rd->m_DevMan.BindSRV(eHWSC_Geometry, pResView, nTUnit); } else { assert(0); } } } } void CTexture::UpdateTextureRegion(const uint8_t* data, int nX, int nY, int nZ, int USize, int VSize, int ZSize, ETEX_Format eTFSrc) { gRenDev->m_pRT->RC_UpdateTextureRegion(this, data, nX, nY, nZ, USize, VSize, ZSize, eTFSrc); } void CTexture::RT_UpdateTextureRegion(const byte* data, int nX, int nY, int nZ, int USize, int VSize, int ZSize, ETEX_Format eTFSrc) { PROFILE_FRAME(UpdateTextureRegion); if (m_eTT != eTT_2D && m_eTT != eTT_3D) { assert(0); return; } HRESULT hr = S_OK; CDeviceTexture* pDevTexture = GetDevTexture(); assert(pDevTexture); if (!pDevTexture) { return; } DXGI_FORMAT frmtSrc = (DXGI_FORMAT)CTexture::DeviceFormatFromTexFormat(eTFSrc); bool bDone = false; D3D11_BOX rc = {aznumeric_caster(nX), aznumeric_caster(nY), 0, aznumeric_caster(nX + USize), aznumeric_caster(nY + VSize), 1}; if (m_eTT == eTT_2D) { if (GetBlockDim(m_eTFDst) == Vec2i(1)) { int nBPPSrc = CTexture::BytesPerBlock(eTFSrc); int nBPPDst = CTexture::BytesPerBlock(m_eTFDst); if (nBPPSrc == nBPPDst) { int nRowPitch = CTexture::TextureDataSize(USize, 1, 1, 1, 1, eTFSrc); const int nSlicePitch = CTexture::TextureDataSize(USize, VSize, 1, 1, 1, eTFSrc); gcpRendD3D->GetDeviceContext().UpdateSubresource(pDevTexture->Get2DTexture(), 0, &rc, data, nRowPitch, nSlicePitch); bDone = true; } else { assert(0); bDone = true; } } } else if (m_eTT == eTT_3D) { int nFrame = gRenDev->m_nFrameSwapID; rc.front = nZ; rc.back = nZ + ZSize; int nBPPSrc = CTexture::BytesPerBlock(eTFSrc); int nBPPDst = CTexture::BytesPerBlock(m_eTFDst); if (nBPPSrc == nBPPDst) { if (m_nFlags & FT_USAGE_DYNAMIC) { D3DVolumeTexture* pDT = pDevTexture->GetVolumeTexture(); int cZ, cY; for (cZ = nZ; cZ < ZSize; cZ++) { D3D11_MAPPED_SUBRESOURCE lrct; uint32 nLockFlags = D3D11_MAP_WRITE_DISCARD; uint32 nSubRes = D3D11CalcSubresource(0, cZ, 1); hr = gcpRendD3D->GetDeviceContext().Map(pDT, nSubRes, (D3D11_MAP)nLockFlags, 0, &lrct); assert(hr == S_OK); byte* pDst = ((byte*)lrct.pData) + nX * 4 + nY * lrct.RowPitch; for (cY = 0; cY < VSize; cY++) { cryMemcpy(pDst, data, USize * 4); data += USize * 4; pDst += lrct.RowPitch; } gcpRendD3D->GetDeviceContext().Unmap(pDT, nSubRes); } } else { int U = USize; int V = VSize; int Z = ZSize; for (int i = 0; i < m_nMips; i++) { if (!U) { U = 1; } if (!V) { V = 1; } if (!Z) { Z = 1; } int nRowPitch = CTexture::TextureDataSize(U, 1, 1, 1, 1, eTFSrc); int nDepthPitch = m_eTT == eTT_3D ? CTexture::TextureDataSize(U, V, 1, 1, 1, eTFSrc) : 0; gcpRendD3D->GetDeviceContext().UpdateSubresource(pDevTexture->GetBaseTexture(), i, &rc, data, nRowPitch, nDepthPitch); bDone = true; data += nDepthPitch * Z; U >>= 1; V >>= 1; Z >>= 1; rc.front >>= 1; rc.left >>= 1; rc.top >>= 1; rc.back = max(rc.front + 1, rc.back >> 1); rc.right = max(rc.left + 4, rc.right >> 1); rc.bottom = max(rc.top + 4, rc.bottom >> 1); } } } else if ((eTFSrc == eTF_B8G8R8A8 || eTFSrc == eTF_B8G8R8X8) && (m_eTFDst == eTF_B5G6R5)) { assert(0); bDone = true; } } if (!bDone) { D3D11_BOX box; ZeroStruct(box); box.right = USize; box.bottom = VSize; box.back = 1; const int nPitch = CTexture::TextureDataSize(USize, 1, 1, 1, 1, eTFSrc); const int nSlicePitch = CTexture::TextureDataSize(USize, VSize, 1, 1, 1, eTFSrc); gcpRendD3D->GetDeviceContext().UpdateSubresource(pDevTexture->Get2DTexture(), 0, &box, data, nPitch, nSlicePitch); } } bool CTexture::Clear() { if (!(m_nFlags & FT_USAGE_RENDERTARGET)) return false; gRenDev->m_pRT->RC_ClearTarget(this, m_cClearColor); return true; } bool CTexture::Clear(const ColorF& color) { if (!(m_nFlags & FT_USAGE_RENDERTARGET)) { return false; } gRenDev->m_pRT->RC_ClearTarget(this, color); return true; } void SEnvTexture::Release() { ReleaseDeviceObjects(); SAFE_DELETE(m_pTex); } void SEnvTexture::RT_SetMatrix() { Matrix44A matView, matProj; gRenDev->GetModelViewMatrix(matView.GetData()); gRenDev->GetProjectionMatrix(matProj.GetData()); float fWidth = m_pTex ? (float)m_pTex->GetWidth() : 1; float fHeight = m_pTex ? (float)m_pTex->GetHeight() : 1; Matrix44A matScaleBias(0.5f, 0, 0, 0, 0, -0.5f, 0, 0, 0, 0, 0.5f, 0, // texel alignment - also push up y axis reflection up a bit 0.5f + 0.5f / fWidth, 0.5f + 1.0f / fHeight, 0.5f, 1.0f); Matrix44A m = matProj * matScaleBias; Matrix44A mm = matView * m; m_Matrix = mm; } void SEnvTexture::ReleaseDeviceObjects() { //if (m_pTex) // m_pTex->ReleaseDynamicRT(true); } #if AZ_RENDER_TO_TEXTURE_GEM_ENABLED bool CTexture::RenderToTexture(int handle, const CCamera& camera, AzRTT::RenderContextId contextId) { if (!CRenderer::CV_r_RTT) { return false; } CTexture* pTex = CTexture::GetByID(handle); if (!pTex || !pTex->GetDevTexture()) { iLog->Log("Failed to render texture. Invalid texture handle ID."); return false; } // a context may be invalid because it requires hardware resources that are not available bool contextIsValid = false; AzRTT::RTTRequestBus::BroadcastResult(contextIsValid, &AzRTT::RTTRequestBus::Events::ContextIsValid, contextId); if (!contextIsValid) { return false; } const int width = pTex->GetWidth(); const int height = pTex->GetHeight(); // NOTE: the renderer's camera comes from the thread info double buffer, so it is possible // GetCamera() will just return the camera using in the last render to texture pass. // System::GetViewCamera() will have the camera used for the main rendering view CCamera prevSysCamera = gEnv->pSystem->GetViewCamera(); // get the current viewport and renderer settings to restore after rendering to texture int vX, vY, vWidth, vHeight; gRenDev->GetViewport(&vX, &vY, &vWidth, &vHeight); // this flag is used by the engine to denote we are rendering the whole scene to texture gcpRendD3D->m_RP.m_TI[gcpRendD3D->m_RP.m_nFillThreadID].m_PersFlags |= RBPF_RENDER_SCENE_TO_TEXTURE; // this resets the view and frame view/proj matrices in the thread info gcpRendD3D->BeginFrame(); // this frees up previous frame render cameras and waits for jobs. It will trigger MainThreadRenderRequestBus::ExecuteQueuedEvents(); // The main pass also calls this after BeginFrame and before RenderWorld gEnv->p3DEngine->Tick(); // set the active camera gRenDev->SetCamera(camera); // set the system view camera CCamera newSystemCamera = camera; gEnv->pSystem->SetViewCamera(newSystemCamera); // we do not call PreWorldStreamUpdate here because it will compare the distance of the rtt // camera to the main camera and negatively affect stream settings gRenDev->m_pRT->EnqueueRenderCommand([=]() { // disable back buffer swap so the renderer doesn't call present gRenDev->EnableSwapBuffers(false); CTexture* pTex = CTexture::GetByID(handle); // when you set the render target SetViewport is also called with the size of the target gRenDev->RT_PushRenderTarget(0, pTex, nullptr, -1); // TODO manually set the viewport with our own viewport ID if we enabled TAA. Currently // doesn't work in multi-threaded mode. Causes flickering vegetation/transparent shadows // disabling temporal effects turns off auto exposure and reduces flicker. gRenDev->m_nDisableTemporalEffects = 1; }); bool contextIsActive = false; AzRTT::RTTRequestBus::BroadcastResult(contextIsActive, &AzRTT::RTTRequestBus::Events::SetActiveContext, contextId); AZ_Warning("RenderToTexture", contextIsActive, "Failed to activate render to texture context, the render target will not be updated"); if (contextIsActive) { // don't draw UI or console to this RTT gEnv->pSystem->SetConsoleDrawEnabled(false); gEnv->pSystem->SetUIDrawEnabled(false); AzRTT::RenderContextConfig config; AzRTT::RTTRequestBus::BroadcastResult(config, &AzRTT::RTTRequestBus::Events::GetContextConfig, contextId); uint32_t renderPassFlags = SRenderingPassInfo::DEFAULT_FLAGS | SRenderingPassInfo::RENDER_SCENE_TO_TEXTURE; // render to texture does not support merged meshes yet renderPassFlags &= ~SRenderingPassInfo::MERGED_MESHES; // do not allow SVO (SHDF_ALLOW_AO) for now int renderFlags = SHDF_ZPASS | SHDF_ALLOWHDR | SHDF_ALLOWPOSTPROCESS | SHDF_ALLOW_WATER; if (!config.m_shadowsEnabled) { renderFlags |= SHDF_NO_SHADOWGEN; renderPassFlags &= ~SRenderingPassInfo::SHADOWS; } if (!config.m_oceanEnabled) { renderPassFlags &= ~SRenderingPassInfo::WATEROCEAN; } if (!config.m_terrainEnabled) { renderPassFlags &= ~SRenderingPassInfo::TERRAIN; } if (!config.m_vegetationEnabled) { renderPassFlags &= ~SRenderingPassInfo::VEGETATION; } SRenderingPassInfo renderPassInfo = SRenderingPassInfo::CreateGeneralPassRenderingInfo(camera, renderPassFlags); gEnv->p3DEngine->RenderWorld(renderFlags, renderPassInfo, __FUNCTION__); gEnv->pSystem->SetConsoleDrawEnabled(true); gEnv->pSystem->SetUIDrawEnabled(true); gEnv->p3DEngine->EndOcclusion(); gEnv->p3DEngine->WorldStreamUpdate(); // NOTE: This is how you could copy from the hdr target to the render target if you wanted no post processing (should probably remove SHDF_ALLOWPOSTPROCESS above) //gRenDev->m_pRT->EnqueueRenderCommand([=]() //{ //PostProcessUtils().StretchRect(CTexture::s_ptexHDRTarget, pTex, false, false, false, false, SPostEffectsUtils::eDepthDownsample_None, false, &gcpRendD3D->m_FullResRect); //}); // this ends up calling FX_FinalComposite which will use our render target for post effects gcpRendD3D->SwitchToNativeResolutionBackbuffer(); } // Pop our render target gcpRendD3D->SetRenderTarget(0); gRenDev->m_pRT->EnqueueRenderCommand([=]() { gcpRendD3D->m_RP.m_TI[gcpRendD3D->m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_RENDER_SCENE_TO_TEXTURE; gcpRendD3D->SetViewport(vX, vY, vWidth, vHeight); // Reset the camera on the render thread or the main thread can get our // camera info after syncing with main. gcpRendD3D->SetCamera(prevSysCamera); }); AzRTT::RTTRequestBus::Broadcast(&AzRTT::RTTRequestBus::Events::SetActiveContext, AzRTT::RenderContextId::CreateNull()); // Free all unused render meshes. Without this you can get lots of fun memory leaks. gRenDev->ForceGC(); // call endframe on the renderer instead of via d3d to bypass drawing messages // set wait to true otherwise EndFrame won't be sent if there is no pending flush condition bool wait = true; gRenDev->m_pRT->RC_EndFrame(wait); // re-enable swap buffers after calling end frame so the main pass will call present() gRenDev->m_pRT->EnqueueRenderCommand([=]() { gRenDev->EnableSwapBuffers(true); }); // normally we would need to remove the cull job producer using RemoveCullJobProducer // we don't need to because we use e_statobjbufferrendertask = 0 // restore previous settings gEnv->pSystem->SetViewCamera(prevSysCamera); gRenDev->SetCamera(prevSysCamera); // this fixes streaming update sync errors when rendering pre frame gEnv->p3DEngine->SyncProcessStreamingUpdate(); return true; } #endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED bool CTexture::RenderEnvironmentCMHDR(int size, Vec3& Pos, TArray& vecData) { #if !defined(CONSOLE) iLog->Log("Start generating a cubemap..."); vecData.SetUse(0); int vX, vY, vWidth, vHeight; gRenDev->GetViewport(&vX, &vY, &vWidth, &vHeight); const int nOldWidth = gRenDev->GetCurrentContextViewportWidth(); const int nOldHeight = gRenDev->GetCurrentContextViewportHeight(); bool bFullScreen = (iConsole->GetCVar("r_Fullscreen")->GetIVal() != 0) && (!gEnv->IsEditor()); gRenDev->ChangeViewport(0, 0, size, size); int nPFlags = gcpRendD3D->m_RP.m_TI[gcpRendD3D->m_RP.m_nProcessThreadID].m_PersFlags; CTexture* ptexGenEnvironmentCM = CTexture::Create2DTexture("$GenEnvironmentCM", size, size, 0, FT_DONT_STREAM, 0, eTF_R16G16B16A16F, eTF_R16G16B16A16F); if (!ptexGenEnvironmentCM || !ptexGenEnvironmentCM->GetDevTexture()) { iLog->Log("Failed generating a cubemap: out of video memory"); gRenDev->ChangeViewport(0, 0, nOldWidth, nOldHeight); SAFE_RELEASE(ptexGenEnvironmentCM); return false; } // Disable/set cvars that can affect cube map generation. This is thread unsafe (we assume editor will not run in mt mode), no other way around at this time // - coverage buffer unreliable for multiple views // - custom view distance ratios ICVar* pCoverageBufferCV = gEnv->pConsole->GetCVar("e_CoverageBuffer"); const int32 nCoverageBuffer = pCoverageBufferCV ? pCoverageBufferCV->GetIVal() : 0; if (pCoverageBufferCV) { pCoverageBufferCV->Set(0); } ICVar* pStatObjBufferRenderTasksCV = gEnv->pConsole->GetCVar("e_StatObjBufferRenderTasks"); const int32 nStatObjBufferRenderTasks = pStatObjBufferRenderTasksCV ? pStatObjBufferRenderTasksCV->GetIVal() : 0; if (pStatObjBufferRenderTasksCV) { pStatObjBufferRenderTasksCV->Set(0); } ICVar* pViewDistRatioCV = gEnv->pConsole->GetCVar("e_ViewDistRatio"); const float fOldViewDistRatio = pViewDistRatioCV ? pViewDistRatioCV->GetFVal() : 1.f; if (pViewDistRatioCV) { pViewDistRatioCV->Set(10000.f); } ICVar* pViewDistRatioVegetationCV = gEnv->pConsole->GetCVar("e_ViewDistRatioVegetation"); const float fOldViewDistRatioVegetation = pViewDistRatioVegetationCV ? pViewDistRatioVegetationCV->GetFVal() : 100.f; if (pViewDistRatioVegetationCV) { pViewDistRatioVegetationCV->Set(10000.f); } ICVar* pLodRatioCV = gEnv->pConsole->GetCVar("e_LodRatio"); const float fOldLodRatio = pLodRatioCV ? pLodRatioCV->GetFVal() : 1.f; if (pLodRatioCV) { pLodRatioCV->Set(1000.f); } Vec3 oldSunDir, oldSunStr, oldSunRGB; float oldSkyKm, oldSkyKr, oldSkyG; if (CRenderer::CV_r_HideSunInCubemaps) { gEnv->p3DEngine->GetSkyLightParameters(oldSunDir, oldSunStr, oldSkyKm, oldSkyKr, oldSkyG, oldSunRGB); gEnv->p3DEngine->SetSkyLightParameters(oldSunDir, oldSunStr, oldSkyKm, oldSkyKr, 1.0f, oldSunRGB, true); // Hide sun disc } const int32 nFlaresCV = CRenderer::CV_r_flares; CRenderer::CV_r_flares = 0; ICVar* pSSDOHalfResCV = gEnv->pConsole->GetCVar("r_ssdoHalfRes"); const int nOldSSDOHalfRes = pSSDOHalfResCV ? pSSDOHalfResCV->GetIVal() : 1; if (pSSDOHalfResCV) { pSSDOHalfResCV->Set(0); } ICVar* pDynamicGI = gEnv->pConsole->GetCVar("e_GI"); const int oldDynamicGIValue = pDynamicGI ? pDynamicGI->GetIVal() : 1; if (pDynamicGI) { pDynamicGI->Set(0); } const int nDesktopWidth = gcpRendD3D->m_deskwidth; const int nDesktopHeight = gcpRendD3D->m_deskheight; gcpRendD3D->m_deskwidth = gcpRendD3D->m_deskheight = size; gcpRendD3D->EnableSwapBuffers(false); for (int nSide = 0; nSide < 6; nSide++) { gcpRendD3D->BeginFrame(); gcpRendD3D->SetViewport(0, 0, size, size); gcpRendD3D->SetWidth(size); gcpRendD3D->SetHeight(size); gcpRendD3D->EF_ClearTargetsLater(FRT_CLEAR, Clr_Transparent); DrawSceneToCubeSide(Pos, size, nSide); // Transfer to sysmem D3D11_BOX srcBox; srcBox.left = 0; srcBox.right = size; srcBox.top = 0; srcBox.bottom = size; srcBox.front = 0; srcBox.back = 1; CDeviceTexture* pDevTextureSrc = CTexture::s_ptexHDRTarget->GetDevTexture(); CDeviceTexture* pDevTextureDst = ptexGenEnvironmentCM->GetDevTexture(); gcpRendD3D->GetDeviceContext().CopySubresourceRegion(pDevTextureDst->Get2DTexture(), 0, 0, 0, 0, pDevTextureSrc->Get2DTexture(), 0, &srcBox); CDeviceTexture* pDstDevTex = ptexGenEnvironmentCM->GetDevTexture(); pDstDevTex->DownloadToStagingResource(0, [&](void* pData, uint32 rowPitch, uint32 slicePitch) { unsigned short* pTarg = (unsigned short*)pData; const uint32 nLineStride = CTexture::TextureDataSize(size, 1, 1, 1, 1, eTF_R16G16B16A16F) / sizeof(unsigned short); // Copy vertically flipped image for (uint32 nLine = 0; nLine < size; ++nLine) { vecData.Copy(&pTarg[((size - 1) - nLine) * nLineStride], nLineStride); } return true; }); gcpRendD3D->EndFrame(); } SAFE_RELEASE(ptexGenEnvironmentCM); // Restore previous states gcpRendD3D->m_deskwidth = nDesktopWidth; gcpRendD3D->m_deskheight = nDesktopHeight; gRenDev->ChangeViewport(0, 0, nOldWidth, nOldHeight); gcpRendD3D->EnableSwapBuffers(true); gcpRendD3D->SetWidth(vWidth); gcpRendD3D->SetHeight(vHeight); gcpRendD3D->RT_SetViewport(vX, vY, vWidth, vHeight); gcpRendD3D->m_RP.m_TI[gcpRendD3D->m_RP.m_nProcessThreadID].m_PersFlags = nPFlags; gcpRendD3D->ResetToDefault(); if (pCoverageBufferCV) { pCoverageBufferCV->Set(nCoverageBuffer); } if (pStatObjBufferRenderTasksCV) { pStatObjBufferRenderTasksCV->Set(nStatObjBufferRenderTasks); } if (pViewDistRatioCV) { pViewDistRatioCV->Set(fOldViewDistRatio); } if (pViewDistRatioVegetationCV) { pViewDistRatioVegetationCV->Set(fOldViewDistRatioVegetation); } if (pLodRatioCV) { pLodRatioCV->Set(fOldLodRatio); } if (CRenderer::CV_r_HideSunInCubemaps) { gEnv->p3DEngine->SetSkyLightParameters(oldSunDir, oldSunStr, oldSkyKm, oldSkyKr, oldSkyG, oldSunRGB, true); } CRenderer::CV_r_flares = nFlaresCV; if (pSSDOHalfResCV) { pSSDOHalfResCV->Set(nOldSSDOHalfRes); } if (pDynamicGI) { pDynamicGI->Set(oldDynamicGIValue); } iLog->Log("Successfully finished generating a cubemap. The cubemap is being compressed in the background and will update automatically when done."); #endif return true; } ////////////////////////////////////////////////////////////////////////// void CTexture::DrawSceneToCubeSide(Vec3& Pos, int tex_size, int side) { const float sCubeVector[6][7] = { { 1, 0, 0, 0, 0, 1, -90}, //posx {-1, 0, 0, 0, 0, 1, 90}, //negx { 0, 1, 0, 0, 0, -1, 0}, //posy { 0, -1, 0, 0, 0, 1, 0}, //negy { 0, 0, 1, 0, 1, 0, 0}, //posz { 0, 0, -1, 0, 1, 0, 0}, //negz }; if (!iSystem) { return; } CRenderer* r = gRenDev; CCamera prevCamera = r->GetCamera(); I3DEngine* eng = gEnv->p3DEngine; Vec3 vForward = Vec3(sCubeVector[side][0], sCubeVector[side][1], sCubeVector[side][2]); Vec3 vUp = Vec3(sCubeVector[side][3], sCubeVector[side][4], sCubeVector[side][5]); Matrix33 matRot = Matrix33::CreateOrientation(vForward, vUp, DEG2RAD(sCubeVector[side][6])); Matrix34 mFinal = Matrix34(matRot, Pos); // Use current viewport camera's near/far to capture what is shown in the editor const CCamera& viewCamera = gEnv->pSystem->GetViewCamera(); const float captureNear = viewCamera.GetNearPlane(); const float captureFar = viewCamera.GetFarPlane(); const float captureFOV = DEG2RAD(90.0f); CCamera captureCamera; captureCamera.SetMatrix(mFinal); captureCamera.SetFrustum(tex_size, tex_size, captureFOV, captureNear, captureFar); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log) { r->Logv(SRendItem::m_RecurseLevel[r->m_RP.m_nProcessThreadID], ".. DrawSceneToCubeSide .. (DrawCubeSide %d)\n", side); } #endif eng->RenderWorld(SHDF_CUBEMAPGEN | SHDF_ALLOWPOSTPROCESS | SHDF_ALLOWHDR | SHDF_ZPASS | SHDF_NOASYNC | SHDF_STREAM_SYNC, SRenderingPassInfo::CreateGeneralPassRenderingInfo(captureCamera, (SRenderingPassInfo::DEFAULT_FLAGS | SRenderingPassInfo::CUBEMAP_GEN)), __FUNCTION__); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log) { r->Logv(SRendItem::m_RecurseLevel[r->m_RP.m_nProcessThreadID], ".. End DrawSceneToCubeSide .. (DrawCubeSide %d)\n", side); } #endif r->SetCamera(prevCamera); } ////////////////////////////////////////////////////////////////////////// void CTexture::DrawCubeSide(Vec3& Pos, int tex_size, int side, float fMaxDist) { const float sCubeVector[6][7] = { { 1, 0, 0, 0, 0, 1, -90}, //posx {-1, 0, 0, 0, 0, 1, 90}, //negx { 0, -1, 0, 0, 0, 1, 0}, //posy { 0, 1, 0, 0, 0, -1, 0}, //negy { 0, 0, 1, 0, 1, 0, 0}, //posz { 0, 0, -1, 0, 1, 0, 0}, //negz }; if (!iSystem) { return; } CRenderer* r = gRenDev; CCamera prevCamera = r->GetCamera(); CCamera tmpCamera = prevCamera; I3DEngine* eng = gEnv->p3DEngine; float fMinDist = 0.25f; Vec3 vForward = Vec3(sCubeVector[side][0], sCubeVector[side][1], sCubeVector[side][2]); Vec3 vUp = Vec3(sCubeVector[side][3], sCubeVector[side][4], sCubeVector[side][5]); Matrix33 matRot = Matrix33::CreateOrientation(vForward, vUp, DEG2RAD(sCubeVector[side][6])); // magic orientation we use in engine Matrix33 matScale = Matrix33::CreateScale(Vec3(1, -1, 1)); matRot = matScale * matRot; tmpCamera.SetMatrix(Matrix34(matRot, Pos)); tmpCamera.SetFrustum(tex_size, tex_size, 90.0f * gf_PI / 180.0f, fMinDist, fMaxDist); int nPersFlags = r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags; int nPersFlags2 = r->m_RP.m_PersFlags2; r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags |= /*RBPF_MIRRORCAMERA | */ RBPF_MIRRORCULL | RBPF_DRAWTOTEXTURE | RBPF_ENCODE_HDR; int nOldZ = CRenderer::CV_r_usezpass; CRenderer::CV_r_usezpass = 0; r->RT_SetViewport(0, 0, tex_size, tex_size); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log) { r->Logv(SRendItem::m_RecurseLevel[r->m_RP.m_nProcessThreadID], ".. DrawLowDetail .. (DrawCubeSide %d)\n", side); } #endif eng->RenderWorld(SHDF_ALLOWHDR | SHDF_NOASYNC | SHDF_STREAM_SYNC, SRenderingPassInfo::CreateGeneralPassRenderingInfo(tmpCamera), __FUNCTION__); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log) { r->Logv(SRendItem::m_RecurseLevel[r->m_RP.m_nProcessThreadID], ".. End DrawLowDetail .. (DrawCubeSide %d)\n", side); } #endif r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags = nPersFlags; r->m_RP.m_PersFlags2 = nPersFlags2; r->SetCamera(prevCamera); CRenderer::CV_r_usezpass = nOldZ; } bool CTexture::GenerateMipMaps(bool bSetOrthoProj, bool bUseHW, bool bNormalMap) { if (!(GetFlags() & FT_FORCE_MIPS) || bSetOrthoProj || !bUseHW || bNormalMap) //todo: implement { return false; } PROFILE_LABEL_SCOPE("GENERATE_MIPS"); PROFILE_SHADER_SCOPE; CDeviceTexture* pTex = GetDevTexture(); if (!pTex) { return false; } D3D11_TEXTURE2D_DESC pDesc; pTex->Get2DTexture()->GetDesc(&pDesc); // all d3d11 devices support autogenmipmaps if (m_pRenderTargetData) { gcpRendD3D->GetDeviceContext().GenerateMips(m_pDeviceShaderResource); } return true; } void CTexture::DestroyZMaps() { //SAFE_RELEASE(s_ptexZTarget); } void CTexture::GenerateZMaps() { if (gcpRendD3D->FX_GetEnabledGmemPath(nullptr)) { // Custom Z-Target for GMEM render path should already be set assert(s_ptexZTarget == CTexture::s_ptexGmemStenLinDepth); return; } int nWidth = gcpRendD3D->m_MainViewport.nWidth; //m_d3dsdBackBuffer.Width; int nHeight = gcpRendD3D->m_MainViewport.nHeight; //m_d3dsdBackBuffer.Height; ETEX_Format eTFZ = CTexture::s_eTFZ; uint32 nFlags = FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_DONT_RELEASE; if (CRenderer::CV_r_msaa) { nFlags |= FT_USAGE_MSAA; } if (!s_ptexZTarget) { s_ptexZTarget = CreateRenderTarget("$ZTarget", nWidth, nHeight, Clr_White, eTT_2D, nFlags, eTFZ); s_ptexFurZTarget = CreateRenderTarget("$FurZTarget", nWidth, nHeight, Clr_White, eTT_2D, nFlags, eTFZ); } else { s_ptexZTarget->m_nFlags = nFlags; s_ptexZTarget->m_nWidth = nWidth; s_ptexZTarget->m_nHeight = nHeight; s_ptexZTarget->CreateRenderTarget(eTFZ, Clr_White); s_ptexFurZTarget->m_nFlags = nFlags; s_ptexFurZTarget->m_nWidth = nWidth; s_ptexFurZTarget->m_nHeight = nHeight; s_ptexFurZTarget->CreateRenderTarget(eTFZ, Clr_White); } } void CTexture::DestroySceneMap() { //SAFE_RELEASE(s_ptexSceneTarget); } void CTexture::GenerateSceneMap(ETEX_Format eTF) { const int32 nWidth = gcpRendD3D->GetWidth(); const int32 nHeight = gcpRendD3D->GetHeight(); uint32 nFlags = FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_USAGE_UNORDERED_ACCESS; nFlags |= FT_USAGE_UNORDERED_ACCESS; if (!s_ptexSceneTarget) { s_ptexSceneTarget = CreateRenderTarget("$SceneTarget", nWidth, nHeight, Clr_Empty, eTT_2D, nFlags, eTF, TO_SCENE_TARGET); } else { s_ptexSceneTarget->m_nFlags = nFlags; s_ptexSceneTarget->m_nWidth = nWidth; s_ptexSceneTarget->m_nHeight = nHeight; s_ptexSceneTarget->CreateRenderTarget(eTF, Clr_Empty); } nFlags &= ~(FT_USAGE_MSAA | FT_USAGE_UNORDERED_ACCESS); // This RT used for all post processes passes and shadow mask (group 0) as well ETEX_Format backbufferFormat; static ICVar* DolbyCvar = gEnv->pConsole->GetCVar("r_HDRDolby"); if (DolbyCvar->GetIVal() == 1) { backbufferFormat = eTF_R10G10B10A2; } else { backbufferFormat = eTF_R8G8B8A8; } // This RT used for all post processes passes and shadow mask (group 0) as well if (!CTexture::IsTextureExist(s_ptexBackBuffer)) { s_ptexBackBuffer = CreateRenderTarget("$BackBuffer", nWidth, nHeight, Clr_Transparent, eTT_2D, nFlags, backbufferFormat, TO_BACKBUFFERMAP); } else { s_ptexBackBuffer->m_nFlags = nFlags; s_ptexBackBuffer->m_nWidth = nWidth; s_ptexBackBuffer->m_nHeight = nHeight; s_ptexBackBuffer->CreateRenderTarget(backbufferFormat, Clr_Transparent); } nFlags &= ~(FT_USAGE_MSAA | FT_USAGE_UNORDERED_ACCESS); // This RT can be used by the Render3DModelMgr if the buffer needs to be persistent if (CRenderer::CV_r_UsePersistentRTForModelHUD > 0) { if (!CTexture::IsTextureExist(s_ptexModelHudBuffer)) { s_ptexModelHudBuffer = CreateRenderTarget("$ModelHUD", nWidth, nHeight, Clr_Transparent, eTT_2D, nFlags, eTF_R8G8B8A8, TO_BACKBUFFERMAP); } else { s_ptexModelHudBuffer->m_nFlags = nFlags; s_ptexModelHudBuffer->m_nWidth = nWidth; s_ptexModelHudBuffer->m_nHeight = nHeight; s_ptexModelHudBuffer->CreateRenderTarget(eTF_R8G8B8A8, Clr_Transparent); } } } void CTexture::GenerateCachedShadowMaps() { StaticArray nResolutions = gRenDev->GetCachedShadowsResolution(); // parse shadow resolutions from cvar { int nCurPos = 0; int nCurRes = 0; string strResolutions = gEnv->pConsole->GetCVar("r_ShadowsCacheResolutions")->GetString(); string strCurRes = strResolutions.Tokenize(" ,;-\t", nCurPos); if (!strCurRes.empty()) { nResolutions.fill(0); while (!strCurRes.empty()) { int nRes = atoi(strCurRes.c_str()); nResolutions[nCurRes] = clamp_tpl(nRes, 0, 16384); strCurRes = strResolutions.Tokenize(" ,;-\t", nCurPos); ++nCurRes; } gRenDev->SetCachedShadowsResolution(nResolutions); } } const ETEX_Format texFormat = gEnv->pConsole->GetCVar("r_ShadowsCacheFormat")->GetIVal() == 0 ? eTF_D32F : eTF_D16; const int cachedShadowsStart = clamp_tpl(CRenderer::CV_r_ShadowsCache, 0, MAX_GSM_LODS_NUM - 1); int gsmCascadeCount = gEnv->pSystem->GetConfigSpec() == CONFIG_LOW_SPEC ? 4 : 5; if (ICVar* pGsmLodsVar = gEnv->pConsole->GetCVar("e_GsmLodsNum")) { gsmCascadeCount = pGsmLodsVar->GetIVal(); } const int cachedCascadesCount = cachedShadowsStart > 0 ? clamp_tpl(gsmCascadeCount - cachedShadowsStart + 1, 0, MAX_GSM_LODS_NUM) : 0; for (int i = 0; i < MAX_GSM_LODS_NUM; ++i) { CTexture*& pTx = s_ptexCachedShadowMap[i]; if (!pTx) { char szName[32]; sprintf_s(szName, "CachedShadowMap_%d", i); pTx = CTexture::CreateTextureObject(szName, nResolutions[i], nResolutions[i], 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_DEPTHSTENCIL | FT_USE_HTILE, texFormat); } pTx->Invalidate(nResolutions[i], nResolutions[i], texFormat); // delete existing texture in case it's not needed anymore if (CTexture::IsTextureExist(pTx) && nResolutions[i] == 0) { pTx->ReleaseDeviceTexture(false); } // allocate texture directly for all cached cascades if (!CTexture::IsTextureExist(pTx) && nResolutions[i] > 0 && i < cachedCascadesCount) { CryLog("Allocating shadow map cache %d x %d: %.2f MB", nResolutions[i], nResolutions[i], sqr(nResolutions[i]) * CTexture::BytesPerBlock(texFormat) / (1024.f * 1024.f)); pTx->CreateRenderTarget(texFormat, Clr_FarPlane); } } // height map AO if (CRenderer::CV_r_HeightMapAO) { const int nTexRes = (int)clamp_tpl(CRenderer::CV_r_HeightMapAOResolution, 0.f, 16384.f); if (!s_ptexHeightMapAODepth[0]) { s_ptexHeightMapAODepth[0] = CTexture::CreateTextureObject("HeightMapAO_Depth_0", nTexRes, nTexRes, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_DEPTHSTENCIL | FT_USE_HTILE, eTF_D16); s_ptexHeightMapAODepth[1] = CTexture::CreateTextureObject("HeightMapAO_Depth_1", nTexRes, nTexRes, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_FORCE_MIPS, eTF_R16); } s_ptexHeightMapAODepth[0]->Invalidate(nTexRes, nTexRes, eTF_D16); s_ptexHeightMapAODepth[1]->Invalidate(nTexRes, nTexRes, eTF_R16); if (!CTexture::IsTextureExist(s_ptexHeightMapAODepth[0]) && nTexRes > 0) { s_ptexHeightMapAODepth[0]->CreateRenderTarget(eTF_D16, Clr_FarPlane); s_ptexHeightMapAODepth[1]->CreateRenderTarget(eTF_R16, Clr_FarPlane); } } if (ShadowFrustumMGPUCache* pShadowMGPUCache = gRenDev->GetShadowFrustumMGPUCache()) { pShadowMGPUCache->nUpdateMaskRT = 0; pShadowMGPUCache->nUpdateMaskMT = 0; } } void CTexture::DestroyCachedShadowMaps() { for (int i = 0; i < MAX_GSM_LODS_NUM; ++i) { SAFE_RELEASE_FORCE(s_ptexCachedShadowMap[i]); } SAFE_RELEASE_FORCE(s_ptexHeightMapAO[0]); SAFE_RELEASE_FORCE(s_ptexHeightMapAO[1]); } void CTexture::GenerateNearestShadowMap() { const int texResolution = CRenderer::CV_r_ShadowsNearestMapResolution; const ETEX_Format texFormat = eTF_D32F; s_ptexNearestShadowMap = CTexture::CreateTextureObject("NearestShadowMap", texResolution, texResolution, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_DEPTHSTENCIL | FT_USE_HTILE, texFormat); } void CTexture::DestroyNearestShadowMap() { if (s_ptexNearestShadowMap) { SAFE_RELEASE_FORCE(s_ptexNearestShadowMap); } } bool SDynTexture::RT_Update(int nNewWidth, int nNewHeight) { AZ_Assert(gRenDev->m_pRT->IsRenderThread(), ("Error - Cannot call SDynTexture::RT_Update from any thread that is not the primary render thread!")); Unlink(); assert(s_iNumTextureBytesCheckedOut + s_iNumTextureBytesCheckedIn == s_nMemoryOccupied); if (nNewWidth != m_nReqWidth || nNewHeight != m_nReqHeight) { if (m_pTexture) { ReleaseDynamicRT(false); } m_pTexture = NULL; m_nReqWidth = nNewWidth; m_nReqHeight = nNewHeight; AdjustRealSize(); } if (!m_pTexture) { int nNeedSpace = CTexture::TextureDataSize(m_nWidth, m_nHeight, 1, 1, 1, m_eTF); if (m_eTT == eTT_Cube) { nNeedSpace *= 6; } SDynTexture* pTX = SDynTexture::s_Root.m_Prev; const uint32 maxDynamicTextureMemory = SDynTexture::s_CurDynTexMaxSize * 1024u * 1024u; if (nNeedSpace + s_nMemoryOccupied > maxDynamicTextureMemory) { // Commit any render target binds/unbinds in case they are still waiting to be set or unset in a shadow state gcpRendD3D->FX_SetActiveRenderTargets(); m_pTexture = GetDynamicRT(); if (!m_pTexture) { bool bFreed = FreeTextures(true, nNeedSpace); if (!bFreed) { bFreed = FreeTextures(false, nNeedSpace); } if (!bFreed) { pTX = SDynTexture::s_Root.m_Next; int nFrame = gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_nFrameUpdateID - 1; while (nNeedSpace + s_nMemoryOccupied > maxDynamicTextureMemory) { if (pTX == &SDynTexture::s_Root) { static int nThrash; if (nThrash != nFrame) { nThrash = nFrame; iLog->Log("Error: Dynamic textures thrashing (try to increase texture pool size - r_DynTexMaxSize)..."); } break; } SDynTexture* pNext = pTX->m_Next; // We cannot unload locked texture or texture used in current frame // Better to increase pool size temporarily if (pTX->m_pTexture && !pTX->m_pTexture->IsActiveRenderTarget()) { if (pTX->m_pTexture->m_nAccessFrameID < nFrame && pTX->m_pTexture->m_nUpdateFrameID < nFrame && !pTX->m_bLocked) { pTX->ReleaseDynamicRT(true); } } pTX = pNext; } } } } } if (!m_pTexture) { m_pTexture = CreateDynamicRT(); } assert(s_iNumTextureBytesCheckedOut + s_iNumTextureBytesCheckedIn == s_nMemoryOccupied); if (m_pTexture) { Link(); return true; } return false; } bool SDynTexture::RT_SetRT(int nRT, int nWidth, int nHeight, bool bPush, bool bScreenVP) { Update(m_nWidth, m_nHeight); SDepthTexture* pDepthSurf = nWidth > 0 ? gcpRendD3D->FX_GetDepthSurface(nWidth, nHeight, false) : &gcpRendD3D->m_DepthBufferOrig; assert(m_pTexture); if (m_pTexture) { if (bPush) { return gcpRendD3D->FX_PushRenderTarget(nRT, m_pTexture, pDepthSurf, -1, bScreenVP); } else { return gcpRendD3D->FX_SetRenderTarget(nRT, m_pTexture, pDepthSurf, false, -1, bScreenVP); } } return false; } bool SDynTexture::SetRT(int nRT, bool bPush, SDepthTexture* pDepthSurf, bool bScreenVP) { Update(m_nWidth, m_nHeight); assert(m_pTexture); if (m_pTexture) { if (bPush) { return gcpRendD3D->FX_PushRenderTarget(nRT, m_pTexture, pDepthSurf, -1, bScreenVP); } else { return gcpRendD3D->FX_SetRenderTarget(nRT, m_pTexture, pDepthSurf, false, -1, bScreenVP); } } return false; } bool SDynTexture::RestoreRT(int nRT, bool bPop) { if (bPop) { return gcpRendD3D->FX_PopRenderTarget(nRT); } else { return gcpRendD3D->FX_RestoreRenderTarget(nRT); } } bool SDynTexture::ClearRT() { gcpRendD3D->FX_ClearTarget(m_pTexture); return true; } bool SDynTexture2::ClearRT() { gcpRendD3D->FX_ClearTarget(m_pTexture); return true; } bool SDynTexture2::SetRT(int nRT, bool bPush, SDepthTexture* pDepthSurf, bool bScreenVP) { Update(m_nWidth, m_nHeight); assert(m_pTexture); if (m_pTexture) { bool bRes = false; if (bPush) { bRes = gcpRendD3D->FX_PushRenderTarget(nRT, m_pTexture, pDepthSurf); } else { bRes = gcpRendD3D->FX_SetRenderTarget(nRT, m_pTexture, pDepthSurf); } SetRectStates(); gcpRendD3D->FX_Commit(); } return false; } bool SDynTexture2::SetRectStates() { assert(m_pTexture); gcpRendD3D->RT_SetViewport(m_nX, m_nY, m_nWidth, m_nHeight); gcpRendD3D->EF_Scissor(true, m_nX, m_nY, m_nWidth, m_nHeight); return true; } bool SDynTexture2::RestoreRT(int nRT, bool bPop) { bool bRes = false; gcpRendD3D->EF_Scissor(false, m_nX, m_nY, m_nWidth, m_nHeight); if (bPop) { bRes = gcpRendD3D->FX_PopRenderTarget(nRT); } else { bRes = gcpRendD3D->FX_RestoreRenderTarget(nRT); } gcpRendD3D->FX_Commit(); return bRes; } void _DrawText(ISystem* pSystem, int x, int y, const float fScale, const char* format, ...); static int __cdecl RTCallback(const VOID* arg1, const VOID* arg2) { CTexture* p1 = *(CTexture**)arg1; CTexture* p2 = *(CTexture**)arg2; // show big textures first int nSize1 = p1->GetDataSize(); int nSize2 = p2->GetDataSize(); if (nSize1 > nSize2) { return -1; } else if (nSize2 > nSize1) { return 1; } return strcmp(p1->GetName(), p2->GetName()); } void CD3D9Renderer::DrawAllDynTextures(const char* szFilter, const bool bLogNames, const bool bOnlyIfUsedThisFrame) { #ifndef _RELEASE SDynTexture2::TextureSet2Itor itor; char name[256]; //, nm[256]; cry_strcpy(name, szFilter); azstrlwr(name, AZ_ARRAY_SIZE(name)); TArray UsedRT; int nMaxCount = CV_r_ShowDynTexturesMaxCount; float width = 800; float height = 600; float fArrDim = max(1.f, sqrtf((float)nMaxCount)); float fPicDimX = width / fArrDim; float fPicDimY = height / fArrDim; float x = 0; float y = 0; TransformationMatrices backupSceneMatrices; Set2DMode(static_cast(width), static_cast(height), backupSceneMatrices); EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); EF_SetSrgbWrite(false); if (name[0] == '*' && !name[1]) { SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName()); ResourcesMapItor it; for (it = pRL->m_RMap.begin(); it != pRL->m_RMap.end(); it++) { CTexture* tp = (CTexture*)it->second; if (tp && !tp->IsNoTexture()) { if ((tp->GetFlags() & (FT_USAGE_RENDERTARGET | FT_USAGE_DYNAMIC)) && tp->GetDevTexture()) { UsedRT.AddElem(tp); } } } } else { SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName()); ResourcesMapItor it; for (it = pRL->m_RMap.begin(); it != pRL->m_RMap.end(); it++) { CTexture* tp = (CTexture*)it->second; if (!tp || tp->IsNoTexture()) { continue; } if ((tp->GetFlags() & (FT_USAGE_RENDERTARGET | FT_USAGE_DYNAMIC)) && tp->GetDevTexture()) { char nameBuffer[128]; cry_strcpy(nameBuffer, tp->GetName()); azstrlwr(nameBuffer, AZ_ARRAY_SIZE(nameBuffer)); if (CryStringUtils::MatchWildcard(nameBuffer, name)) { UsedRT.AddElem(tp); } } } } if (UsedRT.Num() > 1) { qsort(&UsedRT[0], UsedRT.Num(), sizeof(CTexture*), RTCallback); } fPicDimX = width / fArrDim; fPicDimY = height / fArrDim; x = 0; y = 0; for (uint32 i = 0; i < UsedRT.Num(); i++) { SetState(GS_NODEPTHTEST); CTexture* tp = UsedRT[i]; int nSavedAccessFrameID = tp->m_nAccessFrameID; if (bOnlyIfUsedThisFrame) { if (tp->m_nUpdateFrameID < m_RP.m_TI[m_RP.m_nProcessThreadID].m_nFrameUpdateID - 2) { continue; } } if (tp->GetTextureType() == eTT_2D) { Draw2dImage(x, y, fPicDimX - 2, fPicDimY - 2, tp->GetID(), 0, 1, 1, 0, 0); } tp->m_nAccessFrameID = nSavedAccessFrameID; const char* pTexName = tp->GetName(); char nameBuffer[128]; memset(nameBuffer, 0, sizeof nameBuffer); for (int iStr = 0, jStr = 0; pTexName[iStr] && jStr < sizeof nameBuffer - 1; ++iStr) { if (pTexName[iStr] == '$') { nameBuffer[jStr] = '$'; nameBuffer[jStr + 1] = '$'; jStr += 2; } else { nameBuffer[jStr] = pTexName[iStr]; ++jStr; } } nameBuffer[sizeof nameBuffer - 1] = 0; pTexName = nameBuffer; int32 nPosX = (int32)ScaleCoordX(x); int32 nPosY = (int32)ScaleCoordY(y); _DrawText(iSystem, nPosX, nPosY, 1.0f, "%8s", pTexName); _DrawText(iSystem, nPosX, nPosY += 10, 1.0f, "%d-%d", tp->m_nUpdateFrameID, tp->m_nAccessFrameID); _DrawText(iSystem, nPosX, nPosY += 10, 1.0f, "%dx%d", tp->GetWidth(), tp->GetHeight()); if (bLogNames) { iLog->Log("Mem:%d %dx%d Type:%s Format:%s (%s)", tp->GetDeviceDataSize(), tp->GetWidth(), tp->GetHeight(), tp->NameForTextureType(tp->GetTextureType()), tp->NameForTextureFormat(tp->GetDstFormat()), tp->GetName()); } x += fPicDimX; if (x >= width - 10) { x = 0; y += fPicDimY; } } Unset2DMode(backupSceneMatrices); RT_RenderTextMessages(); #endif } void CTexture::ReleaseSystemTargets() { CTexture::DestroyHDRMaps(); CTexture::DestroySceneMap(); CTexture::DestroyCachedShadowMaps(); CTexture::DestroyNearestShadowMap(); if (CDeferredShading::Instance().IsValid()) { CDeferredShading::Instance().DestroyDeferredMaps(); } PostProcessUtils().Release(); SAFE_RELEASE_FORCE(s_ptexWaterOcean); SAFE_RELEASE_FORCE(s_ptexWaterVolumeTemp); SAFE_RELEASE_FORCE(s_ptexWaterRipplesDDN); SAFE_RELEASE_FORCE(s_ptexSceneNormalsMap); SAFE_RELEASE_FORCE(s_ptexSceneNormalsBent); SAFE_RELEASE_FORCE(s_ptexAOColorBleed); SAFE_RELEASE_FORCE(s_ptexSceneDiffuse); SAFE_RELEASE_FORCE(s_ptexSceneSpecular); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_10 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif SAFE_RELEASE_FORCE(s_ptexSceneDiffuseAccMap); SAFE_RELEASE_FORCE(s_ptexSceneSpecularAccMap); SAFE_RELEASE_FORCE(s_ptexBackBuffer); SAFE_RELEASE_FORCE(s_ptexSceneTarget); SAFE_RELEASE_FORCE(s_ptexZTargetScaled); SAFE_RELEASE_FORCE(s_ptexZTargetScaled2); SAFE_RELEASE_FORCE(s_ptexAmbientLookup); SAFE_RELEASE_FORCE(s_ptexDepthBufferQuarter); gcpRendD3D->m_bSystemTargetsInit = 0; } void CTexture::ReleaseMiscTargets() { if (gcpRendD3D->m_pColorGradingControllerD3D) { gcpRendD3D->m_pColorGradingControllerD3D->ReleaseTextures(); } } void CTexture::CreateSystemTargets() { if (!gcpRendD3D->m_bSystemTargetsInit) { gcpRendD3D->m_bSystemTargetsInit = 1; ETEX_Format eTF = (gcpRendD3D->m_RP.m_bUseHDR && gcpRendD3D->m_nHDRType == 1) ? eTF_R16G16B16A16F : eTF_R8G8B8A8; // Create HDR targets CTexture::GenerateHDRMaps(); // Create scene targets CTexture::GenerateSceneMap(eTF); // Create ZTarget CTexture::GenerateZMaps(); // Allocate cached shadow maps if required CTexture::GenerateCachedShadowMaps(); // Allocate the nearest shadow map if required CTexture::GenerateNearestShadowMap(); // Create deferred lighting targets if (CDeferredShading::Instance().IsValid()) { CDeferredShading::Instance().CreateDeferredMaps(); } if (CRenderer::CV_r_DeferredShadingTiled > 0) { gcpRendD3D->GetTiledShading().CreateResources(); } gcpRendD3D->GetVolumetricFog().CreateResources(); // Create post effects targets PostProcessUtils().Create(); } } void CTexture::CopySliceChain(CDeviceTexture* const pDevTexture, int ownerMips, int nDstSlice, int nDstMip, CDeviceTexture* pSrcDevTex, int nSrcSlice, int nSrcMip, int nSrcMips, int nNumMips) { assert(pSrcDevTex && pDevTexture); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_11 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif D3DBaseTexture* pDstResource = pDevTexture->GetBaseTexture(); D3DBaseTexture* pSrcResource = pSrcDevTex->GetBaseTexture(); #ifndef _RELEASE if (!pDstResource) { __debugbreak(); } if (!pSrcResource) { __debugbreak(); } #endif #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DTEXTURE_CPP_SECTION_12 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DTexture_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DTexture_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DTexture_cpp_salem.inl" #endif #endif assert(nSrcMip >= 0 && nDstMip >= 0); for (int i = 0; i < nNumMips; ++i) { #if defined(DEVICE_SUPPORTS_D3D11_1) gcpRendD3D->GetDeviceContext().CopySubresourceRegion1( pDstResource, D3D11CalcSubresource(nDstMip + i, nDstSlice, ownerMips), 0, 0, 0, pSrcResource, D3D11CalcSubresource(nSrcMip + i, nSrcSlice, nSrcMips), NULL, D3D11_COPY_NO_OVERWRITE); #else gcpRendD3D->GetDeviceContext().CopySubresourceRegion( pDstResource, D3D11CalcSubresource(nDstMip + i, nDstSlice, ownerMips), 0, 0, 0, pSrcResource, D3D11CalcSubresource(nSrcMip + i, nSrcSlice, nSrcMips), NULL); #endif } }