You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/Common/Textures/Texture.h

2521 lines
84 KiB
C++

/*
* 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.
// change file hash again
#pragma once
#include <set>
#include "../ResFile.h"
#include "PowerOf2BlockPacker.h"
#include "STLPoolAllocator.h"
#include "ITextureStreamer.h"
#include "TextureArrayAlloc.h"
#include "Image/DDSImage.h"
#include "ImageExtensionHelper.h"
#include <AzCore/Jobs/LegacyJobExecutor.h>
#include <AzCore/std/parallel/atomic.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
#include <RenderContextConfig.h>
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
#define TEXTURE_H_SECTION_1 1
#define TEXTURE_H_SECTION_2 2
#define TEXTURE_H_SECTION_3 3
#define TEXTURE_H_SECTION_4 4
#define TEXTURE_H_SECTION_5 5
#define TEXTURE_H_SECTION_6 6
#define TEXTURE_H_SECTION_7 7
#endif
// Only the editor needs to use a unique mutex per texture.
// In the editor, multiple worker threads could destroy device resource sets which point to the same texture
#if defined(AZ_PLATFORM_WINDOWS)
#define USE_UNIQUE_MUTEX_PER_TEXTURE
#endif
class CTexture;
class CImageFile;
class CTextureStreamPoolMgr;
struct SDepthTexture;
#define TEXPOOL_LOADSIZE 6 * 1024 * 1024
#define MAX_MIP_LEVELS (100)
#define CTEXTURE_RENDER_TARGET_USE_COUNT_NUMBER_BITS 2
// Custom Textures IDs
enum
{
TO_RT_2D = 1,
TO_FOG,
TO_FROMOBJ,
TO_SVOTREE,
TO_SVOTRIS,
TO_SVOGLCM,
TO_SVORGBS,
TO_SVONORM,
TO_SVOOPAC,
TO_FROMOBJ_CM,
TO_SHADOWID0,
TO_SHADOWID1,
TO_SHADOWID2,
TO_SHADOWID3,
TO_SHADOWID4,
TO_SHADOWID5,
TO_SHADOWID6,
TO_SHADOWID7,
TO_FROMRE0,
TO_FROMRE1,
TO_FROMRE0_FROM_CONTAINER,
TO_FROMRE1_FROM_CONTAINER,
TO_SCREENMAP,
TO_SHADOWMASK,
TO_CLOUDS_LM,
TO_BACKBUFFERMAP,
TO_PREVBACKBUFFERMAP0,
TO_PREVBACKBUFFERMAP1,
TO_MIPCOLORS_DIFFUSE,
TO_MIPCOLORS_BUMP,
TO_DOWNSCALED_ZTARGET_FOR_AO,
TO_QUARTER_ZTARGET_FOR_AO,
TO_WATEROCEANMAP,
TO_WATERVOLUMEMAP,
TO_WATERVOLUMEREFLMAP,
TO_WATERVOLUMEREFLMAPPREV,
TO_WATERVOLUMECAUSTICSMAP,
TO_WATERVOLUMECAUSTICSMAPTEMP,
TO_WATERRIPPLESMAP,
TO_VOLOBJ_DENSITY,
TO_VOLOBJ_SHADOW,
TO_COLORCHART,
TO_ZTARGET_MS,
TO_SCENE_NORMALMAP,
TO_SCENE_NORMALMAP_MS,
TO_LPV_R,
TO_LPV_G,
TO_LPV_B,
TO_RSM_NORMAL,
TO_RSM_COLOR,
TO_RSM_DEPTH,
TO_SCENE_DIFFUSE_ACC,
TO_SCENE_SPECULAR_ACC,
TO_SCENE_DIFFUSE_ACC_MS,
TO_SCENE_SPECULAR_ACC_MS,
TO_SCENE_TEXTURES,
TO_SCENE_TARGET,
TO_BACKBUFFERSCALED_D2,
TO_BACKBUFFERSCALED_D4,
TO_BACKBUFFERSCALED_D8,
TO_SKYDOME_MIE,
TO_SKYDOME_RAYLEIGH,
TO_SKYDOME_MOON,
TO_VOLFOGSHADOW_BUF,
TO_HDR_MEASURED_LUMINANCE,
TO_MODELHUD,
TO_DEFAULT_ENVIRONMENT_PROBE,
};
#define NUM_HDR_TONEMAP_TEXTURES 4
#define NUM_HDR_BLOOM_TEXTURES 3
#define MIN_DOF_COC_K 6
#if defined(OPENGL_ES) || defined(CRY_USE_METAL)
#define MAX_OCCLUSION_READBACK_TEXTURES 2
#else
#define MAX_OCCLUSION_READBACK_TEXTURES 8
#endif
#define DYNTEXTURE_TEXCACHE_LIMIT 32
inline int LogBaseTwo(int iNum)
{
int i, n;
for (i = iNum - 1, n = 0; i > 0; i >>= 1, n++)
{
;
}
return n;
}
enum EShadowBuffers_Pool
{
SBP_D16,
SBP_D24S8,
SBP_D32FS8,
SBP_R16G16,
SBP_MAX,
SBP_UNKNOWN
};
//dx9 usages
enum ETexture_Usage
{
eTXUSAGE_AUTOGENMIPMAP,
eTXUSAGE_DEPTHSTENCIL,
eTXUSAGE_RENDERTARGET
};
#define SHADOWS_POOL_SIZE 1024//896 //768
#define TEX_POOL_BLOCKLOGSIZE 5 // 32
#define TEX_POOL_BLOCKSIZE (1 << TEX_POOL_BLOCKLOGSIZE)
struct SDynTexture_Shadow;
struct SDepthTexture;
//======================================================================
// Dynamic textures
struct SDynTexture
: public IDynTexture
{
static uint32 s_nMemoryOccupied;
static SDynTexture s_Root;
SDynTexture* m_Next; //!<
SDynTexture* m_Prev; //!<
char m_sSource[128]; //!< pointer to the given name in the constructor call
CTexture* m_pTexture;
ETEX_Format m_eTF;
ETEX_Type m_eTT;
uint32 m_nWidth;
uint32 m_nHeight;
uint32 m_nReqWidth;
uint32 m_nReqHeight;
uint32 m_nTexFlags;
uint32 m_nFrameReset;
bool m_bLocked;
byte m_nUpdateMask;
//////////////////////////////////////////////////////////////////////////
// Shadow specific vars.
//////////////////////////////////////////////////////////////////////////
int m_nUniqueID;
SDynTexture_Shadow* m_NextShadow; //!<
SDynTexture_Shadow* m_PrevShadow; //!<
ShadowMapFrustum* m_pFrustumOwner;
IRenderNode* pLightOwner;
int nObjectsRenderedCount;
//////////////////////////////////////////////////////////////////////////
SDynTexture(const char* szSource);
SDynTexture(int nWidth, int nHeight, ETEX_Format eTF, ETEX_Type eTT, int nTexFlags, const char* szSource);
~SDynTexture();
//////////////////////////////////////////////////////////////////////////
// Custom new/delete for pool allocator.
//////////////////////////////////////////////////////////////////////////
ILINE void* operator new(size_t nSize);
ILINE void operator delete(void* ptr);
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
virtual int GetTextureID();
virtual bool Update(int nNewWidth, int nNewHeight);
bool RT_Update(int nNewWidth, int nNewHeight);
virtual void Apply(int nTUnit, int nTS = -1);
virtual bool ClearRT();
virtual bool SetRT(int nRT, bool bPush, struct SDepthTexture* pDepthSurf, bool bScreenVP = false);
virtual bool RT_SetRT(int nRT, int nWidth, int nHeight, bool bPush, bool bScreenVP = false);
virtual bool SetRectStates() { return true; }
virtual bool RestoreRT(int nRT, bool bPop);
virtual ITexture* GetTexture() { return (ITexture*)m_pTexture; }
virtual void Release() { delete this; }
virtual void ReleaseForce();
virtual void SetUpdateMask();
virtual void ResetUpdateMask();
virtual bool IsSecondFrame() { return m_nUpdateMask == 3; }
virtual byte GetFlags() const { return 0; }
virtual void GetSubImageRect(uint32& nX, uint32& nY, uint32& nWidth, uint32& nHeight)
{
nX = 0;
nY = 0;
nWidth = m_nWidth;
nHeight = m_nHeight;
}
virtual void GetImageRect(uint32& nX, uint32& nY, uint32& nWidth, uint32& nHeight);
virtual int GetWidth() { return m_nWidth; }
virtual int GetHeight() { return m_nHeight; }
void Lock() { m_bLocked = true; }
void UnLock() { m_bLocked = false; }
virtual void AdjustRealSize();
virtual bool IsValid();
_inline void UnlinkGlobal()
{
if (!m_Next || !m_Prev)
{
return;
}
m_Next->m_Prev = m_Prev;
m_Prev->m_Next = m_Next;
m_Next = m_Prev = NULL;
}
_inline void LinkGlobal(SDynTexture* Before)
{
if (m_Next || m_Prev)
{
return;
}
m_Next = Before->m_Next;
Before->m_Next->m_Prev = this;
Before->m_Next = this;
m_Prev = Before;
}
virtual void Unlink()
{
UnlinkGlobal();
}
virtual void Link()
{
LinkGlobal(&s_Root);
}
ETEX_Format GetFormat() { return m_eTF; }
bool FreeTextures(bool bOldOnly, int nNeedSpace);
typedef AZStd::multimap<unsigned int, CTexture*, AZStd::less<unsigned int>, AZ::AZStdAlloc<AZ::LegacyAllocator>> TextureSubset;
typedef TextureSubset::iterator TextureSubsetItor;
typedef AZStd::multimap<unsigned int, TextureSubset*, AZStd::less<unsigned int>, AZ::AZStdAlloc<AZ::LegacyAllocator>> TextureSet;
typedef TextureSet::iterator TextureSetItor;
static TextureSet s_availableTexturePool2D_BC1;
static TextureSubset s_checkedOutTexturePool2D_BC1;
static TextureSet s_availableTexturePool2D_R8G8B8A8;
static TextureSubset s_checkedOutTexturePool2D_R8G8B8A8;
static TextureSet s_availableTexturePool2D_R32F;
static TextureSubset s_checkedOutTexturePool2D_R32F;
static TextureSet s_availableTexturePool2D_R16F;
static TextureSubset s_checkedOutTexturePool2D_R16F;
static TextureSet s_availableTexturePool2D_R16G16F;
static TextureSubset s_checkedOutTexturePool2D_R16G16F;
static TextureSet s_availableTexturePool2D_R8G8B8A8S;
static TextureSubset s_checkedOutTexturePool2D_R8G8B8A8S;
static TextureSet s_availableTexturePool2D_R16G16B16A16F;
static TextureSubset s_checkedOutTexturePool2D_R16G16B16A16F;
static TextureSet s_availableTexturePool2D_R10G10B10A2;
static TextureSubset s_checkedOutTexturePool2D_R10G10B10A2;
static TextureSet s_availableTexturePool2D_R11G11B10F;
static TextureSubset s_checkedOutTexturePool2D_R11G11B10F;
static TextureSet s_availableTexturePoolCube_R11G11B10F;
static TextureSubset s_checkedOutTexturePoolCube_R11G11B10F;
static TextureSet s_availableTexturePool2D_R8G8S;
static TextureSubset s_checkedOutTexturePool2D_R8G8S;
static TextureSet s_availableTexturePoolCube_R8G8S;
static TextureSubset s_checkedOutTexturePoolCube_R8G8S;
static TextureSet s_availableTexturePool2D_Shadows[SBP_MAX];
static TextureSubset s_checkedOutTexturePool2D_Shadows[SBP_MAX];
static TextureSet s_availableTexturePoolCube_Shadows[SBP_MAX];
static TextureSubset s_checkedOutTexturePoolCube_Shadows[SBP_MAX];
static TextureSet s_availableTexturePool2DCustom_R16G16F;
static TextureSubset s_checkedOutTexturePool2DCustom_R16G16F;
static TextureSet s_availableTexturePoolCube_BC1;
static TextureSubset s_checkedOutTexturePoolCube_BC1;
static TextureSet s_availableTexturePoolCube_R8G8B8A8;
static TextureSubset s_checkedOutTexturePoolCube_R8G8B8A8;
static TextureSet s_availableTexturePoolCube_R32F;
static TextureSubset s_checkedOutTexturePoolCube_R32F;
static TextureSet s_availableTexturePoolCube_R16F;
static TextureSubset s_checkedOutTexturePoolCube_R16F;
static TextureSet s_availableTexturePoolCube_R16G16F;
static TextureSubset s_checkedOutTexturePoolCube_R16G16F;
static TextureSet s_availableTexturePoolCube_R8G8B8A8S;
static TextureSubset s_checkedOutTexturePoolCube_R8G8B8A8S;
static TextureSet s_availableTexturePoolCube_R16G16B16A16F;
static TextureSubset s_checkedOutTexturePoolCube_R16G16B16A16F;
static TextureSet s_availableTexturePoolCube_R10G10B10A2;
static TextureSubset s_checkedOutTexturePoolCube_R10G10B10A2;
static TextureSet s_availableTexturePoolCubeCustom_R16G16F;
static TextureSubset s_checkedOutTexturePoolCubeCustom_R16G16F;
static uint32 s_iNumTextureBytesCheckedOut;
static uint32 s_iNumTextureBytesCheckedIn;
static uint32 s_SuggestedDynTexAtlasCloudsMaxsize;
static uint32 s_SuggestedTexAtlasSize;
static uint32 s_SuggestedDynTexMaxSize;
static uint32 s_CurDynTexAtlasCloudsMaxsize;
static uint32 s_CurTexAtlasSize;
static uint32 s_CurDynTexMaxSize;
CTexture* CreateDynamicRT();
CTexture* GetDynamicRT();
void ReleaseDynamicRT(bool bForce);
EShadowBuffers_Pool ConvertTexFormatToShadowsPool(ETEX_Format e);
static bool FreeAvailableDynamicRT(int nNeedSpace, TextureSet* pSet, bool bOldOnly);
static void ShutDown();
static void Init();
static void Tick();
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
};
typedef stl::PoolAllocatorNoMT<sizeof(SDynTexture)> SDynTexture_PoolAlloc;
extern SDynTexture_PoolAlloc* g_pSDynTexture_PoolAlloc;
//////////////////////////////////////////////////////////////////////////
// Custom new/delete for pool allocator.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
inline void* SDynTexture::operator new(size_t nSize)
{
void* ptr = g_pSDynTexture_PoolAlloc->Allocate();
if (ptr)
{
memset(ptr, 0, nSize); // Clear objects memory.
}
return ptr;
}
//////////////////////////////////////////////////////////////////////////
inline void SDynTexture::operator delete(void* ptr)
{
if (ptr)
{
g_pSDynTexture_PoolAlloc->Deallocate(ptr);
}
}
//==============================================================================
enum ETexPool : int
{
eTP_Clouds,
eTP_Sprites,
eTP_Max
};
struct STextureSetFormat
{
struct SDynTexture2* m_pRoot;
ETEX_Format m_eTF;
ETexPool m_eTexPool;
ETEX_Type m_eTT;
int m_nTexFlags;
std::vector<CPowerOf2BlockPacker*> m_TexPools;
STextureSetFormat(ETEX_Format eTF, ETexPool eTexPool, uint32 nTexFlags)
{
m_eTF = eTF;
m_eTexPool = eTexPool;
m_eTT = eTT_2D;
m_pRoot = NULL;
m_nTexFlags = nTexFlags;
}
~STextureSetFormat();
};
struct SDynTexture2
: public IDynTexture
{
#ifndef _DEBUG
char* m_sSource; //!< pointer to the given name in the constructor call
#else
char m_sSource[128]; //!< pointer to the given name in the constructor call
#endif
STextureSetFormat* m_pOwner;
CPowerOf2BlockPacker* m_pAllocator;
CTexture* m_pTexture;
uint32 m_nBlockID;
ETexPool m_eTexPool;
SDynTexture2* m_Next; //!<
SDynTexture2** m_PrevLink; //!<
void UnlinkGlobal()
{
if (m_Next)
{
m_Next->m_PrevLink = m_PrevLink;
}
if (m_PrevLink)
{
*m_PrevLink = m_Next;
}
}
void LinkGlobal(SDynTexture2*& Before)
{
if (Before)
{
Before->m_PrevLink = &m_Next;
}
m_Next = Before;
m_PrevLink = &Before;
Before = this;
}
void Link()
{
LinkGlobal(m_pOwner->m_pRoot);
}
void Unlink()
{
UnlinkGlobal();
m_Next = NULL;
m_PrevLink = NULL;
}
bool Remove();
virtual bool IsValid();
bool _IsValid() { return IsValid(); }
SDynTexture2(uint32 nWidth, uint32 nHeight, uint32 nTexFlags, const char* szSource, ETexPool eTexPool);
SDynTexture2(const char* szSource, ETexPool eTexPool);
~SDynTexture2();
bool UpdateAtlasSize(int nNewWidth, int nNewHeight);
void ReleaseForce();
virtual bool Update(int nNewWidth, int nNewHeight);
virtual void Apply(int nTUnit, int nTS = -1);
virtual bool ClearRT();
virtual bool SetRT(int nRT, bool bPush, SDepthTexture* pDepthSurf, bool bScreenVP = false);
virtual bool SetRectStates();
virtual bool RestoreRT(int nRT, bool bPop);
virtual ITexture* GetTexture() { return (ITexture*)m_pTexture; }
ETEX_Format GetFormat() { return m_pOwner->m_eTF; }
virtual void SetUpdateMask();
virtual void ResetUpdateMask();
virtual bool IsSecondFrame() { return m_nUpdateMask == 3; }
virtual byte GetFlags() const { return m_nFlags; }
virtual void SetFlags(byte flags) { m_nFlags = flags; }
// IDynTexture implementation
virtual void Release() { delete this; }
virtual void GetSubImageRect(uint32& nX, uint32& nY, uint32& nWidth, uint32& nHeight)
{
nX = m_nX;
nY = m_nY;
nWidth = m_nWidth;
nHeight = m_nHeight;
}
virtual void GetImageRect(uint32& nX, uint32& nY, uint32& nWidth, uint32& nHeight);
virtual int GetTextureID();
virtual void Lock() { m_bLocked = true; }
virtual void UnLock() { m_bLocked = false; }
virtual int GetWidth() { return m_nWidth; }
virtual int GetHeight() { return m_nHeight; }
typedef std::map<uint32, STextureSetFormat*> TextureSet2;
typedef TextureSet2::iterator TextureSet2Itor;
static AZStd::unique_ptr<TextureSet2> s_TexturePool[eTP_Max];
static int s_nMemoryOccupied[eTP_Max];
static void ShutDown();
static void Init(ETexPool eTexPool);
static int GetPoolMaxSize(ETexPool eTexPool);
static void SetPoolMaxSize(ETexPool eTexPool, int nSize, bool bWarn);
static const char* GetPoolName(ETexPool eTexPool);
static ETEX_Format GetPoolTexFormat(ETexPool eTexPool);
static int GetPoolTexNum(ETexPool eTexPool)
{
int nT = 0;
for (TextureSet2Itor it = s_TexturePool[eTexPool]->begin(); it != s_TexturePool[eTexPool]->end(); it++)
{
STextureSetFormat* pF = it->second;
nT += pF->m_TexPools.size();
}
return nT;
}
uint32 m_nX;
uint32 m_nY;
uint32 m_nWidth;
uint32 m_nHeight;
bool m_bLocked;
byte m_nFlags;
byte m_nUpdateMask; // Crossfire odd/even frames
uint32 m_nFrameReset;
uint32 m_nAccessFrame;
};
//////////////////////////////////////////////////////////////////////////
// Dynamic texture for the shadow.
// This class must not contain any non static member variables,
// because SDynTexture allocated used constant size pool.
//////////////////////////////////////////////////////////////////////////
struct SDynTexture_Shadow
: public SDynTexture
{
static SDynTexture_Shadow s_RootShadow;
//////////////////////////////////////////////////////////////////////////
SDynTexture_Shadow(int nWidth, int nHeight, ETEX_Format eTF, ETEX_Type eTT, int nTexFlags, const char* szSource);
SDynTexture_Shadow(const char* szSource);
~SDynTexture_Shadow();
_inline void UnlinkShadow()
{
//assert(gRenDev->m_pRT->IsRenderThread());
if (!m_NextShadow || !m_PrevShadow)
{
return;
}
m_NextShadow->m_PrevShadow = m_PrevShadow;
m_PrevShadow->m_NextShadow = m_NextShadow;
m_NextShadow = m_PrevShadow = NULL;
}
_inline void LinkShadow(SDynTexture_Shadow* Before)
{
assert(gRenDev->m_pRT->IsRenderThread());
if (m_NextShadow || m_PrevShadow)
{
return;
}
m_NextShadow = Before->m_NextShadow;
Before->m_NextShadow->m_PrevShadow = this;
Before->m_NextShadow = this;
m_PrevShadow = Before;
}
SDynTexture_Shadow* GetByID(int nID)
{
assert(gRenDev->m_pRT->IsRenderThread());
SDynTexture_Shadow* pTX = SDynTexture_Shadow::s_RootShadow.m_NextShadow;
for (pTX = SDynTexture_Shadow::s_RootShadow.m_NextShadow; pTX != &SDynTexture_Shadow::s_RootShadow; pTX = pTX->m_NextShadow)
{
if (pTX->m_nUniqueID == nID)
{
return pTX;
}
}
return NULL;
}
static void RT_EntityDelete(IRenderNode* pRenderNode);
virtual void Unlink()
{
assert(gRenDev->m_pRT->IsRenderThread());
UnlinkGlobal();
UnlinkShadow();
}
virtual void Link()
{
assert(gRenDev->m_pRT->IsRenderThread());
LinkGlobal(&s_Root);
LinkShadow(&s_RootShadow);
}
virtual void AdjustRealSize();
void GetMemoryUsage(ICrySizer* pSizer) const
{
SDynTexture::GetMemoryUsage(pSizer);
}
static SDynTexture_Shadow* GetForFrustum(ShadowMapFrustum* pFrustum);
static void ShutDown();
};
//==========================================================================
// Texture
struct STexCacheFileHeader
{
int8 m_nSides;
int8 m_nMipsPersistent;
STexCacheFileHeader()
{
m_nSides = 0;
m_nMipsPersistent = 0;
}
};
struct SMipData
{
public:
byte* DataArray; // Data.
bool m_bNative : 1;
SMipData()
: m_bNative(false)
, DataArray(NULL)
{}
~SMipData()
{
Free();
}
void Free()
{
SAFE_DELETE_ARRAY(DataArray);
m_bNative = false;
}
void Init(int InSize, [[maybe_unused]] int nWidth, [[maybe_unused]] int nHeight)
{
assert(DataArray == NULL);
DataArray = new byte[InSize];
m_bNative = false;
}
};
struct STexPool;
struct STexPoolItem;
struct STexStreamRoundInfo
{
STexStreamRoundInfo()
{
nRoundUpdateId = -1;
bHighPriority = false;
bLastHighPriority = false;
}
int32 nRoundUpdateId : 30;
uint32 bHighPriority : 1;
uint32 bLastHighPriority : 1;
};
struct STexStreamZoneInfo
{
STexStreamZoneInfo()
{
fMinMipFactor = fLastMinMipFactor = 1000000.f;
}
float fMinMipFactor;
float fLastMinMipFactor;
};
struct STexMipHeader
{
uint32 m_SideSizeWithMips : 31;
uint32 m_InPlaceStreamable : 1;
uint32 m_SideSize : 29;
uint32 m_eMediaType : 3;
#if defined(TEXSTRM_STORE_DEVSIZES)
uint32 m_DevSideSizeWithMips;
#endif
SMipData* m_Mips;
STexMipHeader()
{
m_SideSizeWithMips = 0;
m_InPlaceStreamable = 0;
m_SideSize = 0;
m_eMediaType = 0;
#if defined(TEXSTRM_STORE_DEVSIZES)
m_DevSideSizeWithMips = 0;
#endif
m_Mips = NULL;
}
~STexMipHeader()
{
SAFE_DELETE_ARRAY(m_Mips);
}
};
struct STexStreamingInfo
{
STexStreamZoneInfo m_arrSPInfo[MAX_PREDICTION_ZONES];
STexPoolItem* m_pPoolItem;
uint32 m_nSrcStart;
STexMipHeader* m_pMipHeader;
DDSSplitted::DDSDesc m_desc;
float m_fMinMipFactor;
STexStreamingInfo(){}
STexStreamingInfo(const uint8 nMips)
{
m_pPoolItem = NULL;
// +1 to accomodate queries for the size of the texture with no mips
m_pMipHeader = new STexMipHeader[nMips + 1];
m_nSrcStart = 0;
m_fMinMipFactor = 0.0f;
}
~STexStreamingInfo()
{
SAFE_DELETE_ARRAY(m_pMipHeader);
}
void GetMemoryUsage(ICrySizer* pSizer, int nMips, int nSides) const
{
pSizer->AddObject(this, sizeof(*this));
pSizer->AddObject(m_pMipHeader, sizeof(STexMipHeader) * nMips);
for (int i = 0; i < nMips; i++)
{
pSizer->AddObject(m_pMipHeader[i].m_Mips, sizeof(SMipData) * nSides);
for (int j = 0; j < nSides; j++)
{
pSizer->AddObject(m_pMipHeader[i].m_Mips[j].DataArray, m_pMipHeader[i].m_SideSize);
}
}
}
int GetSize(int nMips, int nSides)
{
int nSize = sizeof(*this);
for (int i = 0; i < nMips; i++)
{
nSize += sizeof(m_pMipHeader[i]);
for (int j = 0; j < nSides; j++)
{
nSize += sizeof(m_pMipHeader[i].m_Mips[j]);
if (m_pMipHeader[i].m_Mips[j].DataArray)
{
nSize += m_pMipHeader[i].m_SideSize;
}
}
}
return nSize;
}
void* operator new ([[maybe_unused]] size_t sz, void* p){ return p; }
void operator delete ([[maybe_unused]] void* ptr, [[maybe_unused]] void* p){}
private:
void* operator new (size_t sz);
void operator delete ([[maybe_unused]] void* ptr){__debugbreak(); }
};
struct STexStreamInMipState
{
uint32 m_nSideDelta : 28;
bool m_bStreamInPlace : 1;
bool m_bExpanded : 1;
bool m_bUploaded : 1;
STexStreamInMipState()
{
m_nSideDelta = 0;
m_bStreamInPlace = false;
m_bExpanded = false;
m_bUploaded = false;
}
};
struct STexStreamInState
: public IStreamCallback
{
public:
enum
{
MaxMips = 12,
MaxStreams = MaxMips * 6,
};
public:
STexStreamInState();
void Reset();
bool TryCommit();
virtual void StreamAsyncOnComplete (IReadStream* pStream, unsigned nError);
#ifdef TEXSTRM_ASYNC_TEXCOPY
void CopyMips();
#endif
public:
CTexture* m_pTexture;
STexPoolItem* m_pNewPoolItem;
volatile int m_nAsyncRefCount;
uint8 m_nHigherUploadedMip;
uint8 m_nLowerUploadedMip;
uint8 m_nActivateMip;
bool m_bAborted;
bool m_bValidLowMips;
volatile bool m_bAllStreamsComplete;
#if defined(TEXSTRM_COMMIT_COOLDOWN)
int m_nStallFrames;
#endif
#ifndef _RELEASE
float m_fStartTime;
#endif
#if defined(TEXSTRM_DEFERRED_UPLOAD)
ID3D11CommandList* m_pCmdList;
#endif
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION TEXTURE_H_SECTION_1
#include AZ_RESTRICTED_FILE(Texture_h)
#endif
IReadStreamPtr m_pStreams[MaxStreams];
STexStreamInMipState m_mips[MaxMips];
};
struct STexStreamPrepState
: IImageFileStreamCallback
{
public:
STexStreamPrepState()
: m_bCompleted(false)
, m_bFailed(false)
, m_bNeedsFinalise(false)
{
}
bool Commit();
public: // IImageFileStreamCallback Members
virtual void OnImageFileStreamComplete(CImageFile* pImFile);
public:
_smart_ptr<CTexture> m_pTexture;
_smart_ptr<CImageFile> m_pImage;
volatile bool m_bCompleted;
volatile bool m_bFailed;
volatile bool m_bNeedsFinalise;
private:
STexStreamPrepState(const STexStreamPrepState&);
STexStreamPrepState& operator = (const STexStreamPrepState&);
};
#ifdef TEXSTRM_ASYNC_TEXCOPY
struct STexStreamOutState
{
public:
void Reset();
bool TryCommit();
void CopyMips();
public:
AZ::LegacyJobExecutor m_jobExecutor;
CTexture* m_pTexture;
STexPoolItem* m_pNewPoolItem;
uint8 m_nStartMip;
volatile bool m_bDone;
volatile bool m_bAborted;
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION TEXTURE_H_SECTION_2
#include AZ_RESTRICTED_FILE(Texture_h)
#endif
};
#endif
//===================================================================
struct SEnvTexture
{
bool m_bInprogress;
bool m_bReady;
bool m_bWater;
bool m_bReflected;
bool m_bReserved;
int m_MaskReady;
int m_Id;
int m_TexSize;
// Result Cube-Map or 2D RT texture
SDynTexture* m_pTex;
float m_TimeLastUpdated;
Vec3 m_CamPos;
Vec3 m_ObjPos;
Ang3 m_Angle;
int m_nFrameReset;
Matrix44 m_Matrix;
//void *m_pQuery[6];
//void *m_pRenderTargets[6];
// Cube maps average colors (used for RT radiosity)
int m_nFrameCreated[6];
ColorF m_EnvColors[6];
SEnvTexture()
{
m_bInprogress = false;
m_bReady = false;
m_bWater = false;
m_bReflected = false;
m_bReserved = false;
m_MaskReady = 0;
m_Id = 0;
m_pTex = NULL;
m_nFrameReset = -1;
m_CamPos.Set(0.0f, 0.0f, 0.0f);
m_ObjPos.Set(0.0f, 0.0f, 0.0f);
m_Angle.Set(0.0f, 0.0f, 0.0f);
for (int i = 0; i < 6; i++)
{
//m_pQuery[i] = NULL;
m_nFrameCreated[i] = -1;
//m_pRenderTargets[i] = NULL;
}
}
void Release();
void ReleaseDeviceObjects();
void RT_SetMatrix();
};
//===============================================================================
struct SPixFormat
{
// Pixel format info.
D3DFormat DeviceFormat;// Pixel format from Direct3D.
const char* Desc; // Stat: Human readable name for stats.
int8 BytesPerBlock;// Total bits per pixel.
uint8 bCanDS : 1;
uint8 bCanRT : 1;
uint8 bCanMultiSampleRT : 1;
uint8 bCanMipsAutoGen : 1;
uint8 bCanReadSRGB : 1;
uint8 bCanGather : 1;
uint8 bCanGatherCmp : 1;
uint8 bCanBlend : 1;
int16 MaxWidth;
int16 MaxHeight;
SPixFormat* Next;
SPixFormat()
{
Init();
}
void Init()
{
BytesPerBlock = 0;
DeviceFormat = (D3DFormat)0;
Desc = NULL;
Next = NULL;
bCanDS = false;
bCanRT = false;
bCanMultiSampleRT = false;
bCanMipsAutoGen = false;
bCanReadSRGB = false;
bCanGather = false;
bCanGatherCmp = false;
bCanBlend = false;
}
bool IsValid() const
{
if (BytesPerBlock)
{
return true;
}
return false;
}
bool CheckSupport(D3DFormat Format, const char* szDescr, ETexture_Usage eTxUsage = eTXUSAGE_AUTOGENMIPMAP);
};
struct SPixFormatSupport
{
SPixFormat m_FormatA8; //8 bit alpha
SPixFormat m_FormatR8;
SPixFormat m_FormatR8S;
SPixFormat m_FormatR8G8; //16 bit
SPixFormat m_FormatR8G8S; //16 bit
SPixFormat m_FormatR8G8B8A8; //32 bit
SPixFormat m_FormatR8G8B8A8S; //32 bit
SPixFormat m_FormatR10G10B10A2; //32 bit
SPixFormat m_FormatR16; //16 bit
SPixFormat m_FormatR16U; //16 bit
SPixFormat m_FormatR16G16U; //32 bit
SPixFormat m_FormatR10G10B10A2UI; //32 bit
SPixFormat m_FormatR16F; //16 bit
SPixFormat m_FormatR32F; //32 bit
SPixFormat m_FormatR16G16; //32 bit
SPixFormat m_FormatR16G16S; //32 bit
SPixFormat m_FormatR16G16F; //32 bit
SPixFormat m_FormatR11G11B10F; //32 bit
SPixFormat m_FormatR16G16B16A16F; //64 bit
SPixFormat m_FormatR16G16B16A16; //64 bit
SPixFormat m_FormatR16G16B16A16S; //64 bit
SPixFormat m_FormatR32G32B32A32F; //128 bit
SPixFormat m_FormatBC1; //Compressed RGB
SPixFormat m_FormatBC2; //Compressed RGBA
SPixFormat m_FormatBC3; //Compressed RGBA
SPixFormat m_FormatBC4U; // ATI1, single channel compression, unsigned
SPixFormat m_FormatBC4S; // ATI1, single channel compression, signed
SPixFormat m_FormatBC5U; //
SPixFormat m_FormatBC5S; //
SPixFormat m_FormatBC6UH; //Compressed RGB
SPixFormat m_FormatBC6SH; //Compressed RGB
SPixFormat m_FormatBC7; //Compressed RGBA
SPixFormat m_FormatR9G9B9E5; //Shared exponent RGB
SPixFormat m_FormatEAC_R11; //EAC compressed single channel for mobile
SPixFormat m_FormatEAC_RG11; //EAC compressed dual channel for mobile
SPixFormat m_FormatETC2; //ETC2 compressed RGB for mobile
SPixFormat m_FormatETC2A; //ETC2a compressed RGBA for mobile
SPixFormat m_FormatD16; //16bit fixed point depth
SPixFormat m_FormatD24S8; //24bit fixed point depth + 8bit stencil
SPixFormat m_FormatD32F; //32bit floating point depth
SPixFormat m_FormatD32FS8; //32bit floating point depth + 8bit stencil
SPixFormat m_FormatB5G6R5; //16 bit
SPixFormat m_FormatB5G5R5; //16 bit
SPixFormat m_FormatB4G4R4A4; //16 bit
SPixFormat m_FormatB8G8R8X8; //32 bit
SPixFormat m_FormatB8G8R8A8; //32 bit
#ifdef CRY_USE_METAL
SPixFormat m_FormatPVRTC2; //ETC2 compressed RGB for mobile
SPixFormat m_FormatPVRTC4; //ETC2a compressed RGBA for mobile
#endif
#if defined(ANDROID) || defined(CRY_USE_METAL)
SPixFormat m_FormatASTC_4x4;
SPixFormat m_FormatASTC_5x4;
SPixFormat m_FormatASTC_5x5;
SPixFormat m_FormatASTC_6x5;
SPixFormat m_FormatASTC_6x6;
SPixFormat m_FormatASTC_8x5;
SPixFormat m_FormatASTC_8x6;
SPixFormat m_FormatASTC_8x8;
SPixFormat m_FormatASTC_10x5;
SPixFormat m_FormatASTC_10x6;
SPixFormat m_FormatASTC_10x8;
SPixFormat m_FormatASTC_10x10;
SPixFormat m_FormatASTC_12x10;
SPixFormat m_FormatASTC_12x12;
#endif
SPixFormat* m_FirstPixelFormat;
void CheckFormatSupport();
};
struct STexStageInfo
{
int m_nCurState;
CDeviceTexture* m_DevTexture;
STexState m_State;
float m_fMipBias;
#if !defined(NULL_RENDERER)
D3DShaderResourceView* m_pCurResView;
EHWShaderClass m_eHWSC;
#endif
STexStageInfo()
{
Flush();
}
void Flush()
{
m_nCurState = -1;
m_State.m_nMipFilter = -1;
m_State.m_nMinFilter = -1;
m_State.m_nMagFilter = -1;
m_State.m_nAddressU = -1;
m_State.m_nAddressV = -1;
m_State.m_nAddressW = -1;
m_State.m_nAnisotropy = 0;
#if !defined(NULL_RENDERER)
m_pCurResView = NULL;
m_eHWSC = eHWSC_Pixel;
#endif
m_DevTexture = NULL;
m_fMipBias = 0.f;
}
};
struct STexData
{
const byte* m_pData[6];
uint16 m_nWidth;
uint16 m_nHeight;
uint16 m_nDepth;
protected:
uint8 m_reallocated;
public:
ETEX_Format m_eTF;
uint8 m_nMips;
int m_nFlags;
float m_fAvgBrightness;
ColorF m_cMinColor;
ColorF m_cMaxColor;
const char* m_pFilePath;
STexData()
{
m_pData[0] = m_pData[1] = m_pData[2] = m_pData[3] = m_pData[4] = m_pData[5] = 0;
m_nWidth = 0;
m_nHeight = 0;
m_nDepth = 1;
m_reallocated = 0;
m_eTF = eTF_Unknown;
m_nMips = 0;
m_nFlags = 0;
m_fAvgBrightness = 1.0f;
m_cMinColor = 0.0f;
m_cMaxColor = 1.0f;
m_pFilePath = 0;
}
void AssignData(unsigned int i, const byte* pNewData)
{
assert(i < 6);
if (WasReallocated(i))
{
delete [] m_pData[i];
}
m_pData[i] = pNewData;
SetReallocated(i);
}
bool WasReallocated(unsigned int i) const
{
return (m_reallocated & (1 << i)) != 0;
}
void SetReallocated(unsigned int i)
{
m_reallocated |= (1 << i);
}
};
struct SDepthTexture
{
int nWidth;
int nHeight;
bool bBusy;
int nFrameAccess;
D3DTexture* pTarget;
D3DDepthSurface* pSurf;
CTexture* pTex;
SDepthTexture()
: nWidth(0)
, nHeight(0)
, bBusy(false)
, nFrameAccess(-1)
, pTarget(nullptr)
, pSurf(nullptr)
, pTex(nullptr)
{}
void Release(bool bReleaseTex = false);
~SDepthTexture();
};
struct DirtyRECT
{
RECT srcRect;
uint16 dstX;
uint16 dstY;
};
struct SResourceView
{
typedef uint64 KeyType;
static const KeyType DefaultView = (KeyType) - 1LL;
static const KeyType DefaultViewMS = (KeyType) - 2LL;
static const KeyType DefaultViewSRGB = (KeyType) - 3LL;
enum ResourceViewType
{
eShaderResourceView = 0,
eRenderTargetView,
eDepthStencilView,
eUnorderedAccessView,
eNumResourceViews
};
union ResourceViewDesc
{
struct
{
uint64 eViewType : 3;
uint64 nFormat : 7;
uint64 nFirstSlice : 11;
uint64 nSliceCount : 11;
uint64 nMostDetailedMip : 4;
uint64 nMipCount : 4;
uint64 bSrgbRead : 1;
uint64 bMultisample : 1;
uint64 nFlags : 2;
uint64 nUnused : 20;
};
KeyType Key;
};
SResourceView(uint64 nKey = DefaultView)
{
COMPILE_TIME_ASSERT(sizeof(m_Desc) <= sizeof(KeyType));
m_Desc.Key = nKey;
m_pDeviceResourceView = NULL;
}
static SResourceView ShaderResourceView(ETEX_Format nFormat, int nFirstSlice = 0, int nSliceCount = -1, int nMostDetailedMip = 0, int nMipCount = -1, bool bSrgbRead = false, bool bMultisample = false);
static SResourceView RenderTargetView(ETEX_Format nFormat, int nFirstSlice = 0, int nSliceCount = -1, int nMipLevel = 0, bool bMultisample = false);
static SResourceView DepthStencilView(ETEX_Format nFormat, int nFirstSlice = 0, int nSliceCount = -1, int nMipLevel = 0, int nFlags = 0, bool bMultisample = false);
static SResourceView UnorderedAccessView(ETEX_Format nFormat, int nFirstSlice = 0, int nSliceCount = -1, int nMipLevel = 0, int nFlags = 0);
bool operator==(const SResourceView& other) const
{
return m_Desc.Key == other.m_Desc.Key;
}
ResourceViewDesc m_Desc;
void* m_pDeviceResourceView;
};
// properties of the render targets ONLY
struct RenderTargetData
{
int m_nRTSetFrameID; // last read access, compare with GetFrameID(false)
struct
{
uint8 m_nMSAASamples : 4;
uint8 m_nMSAAQuality : 4;
};
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION TEXTURE_H_SECTION_3
#include AZ_RESTRICTED_FILE(Texture_h)
#endif
TArray<SResourceView> m_ResourceViews;
CDeviceTexture* m_pDeviceTextureMSAA;
RenderTargetData()
{
memset(this, 0, sizeof(*this));
m_nRTSetFrameID = -1;
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION TEXTURE_H_SECTION_4
#include AZ_RESTRICTED_FILE(Texture_h)
#endif
}
~RenderTargetData();
};
//////////////////////////////////////////////////////////////////////////
struct SStreamFormatCodeKey
{
union
{
struct
{
uint16 nWidth;
uint16 nHeight;
ETEX_Format fmt;
uint8 nTailMips;
} s;
uint64 u;
};
SStreamFormatCodeKey(uint32 nWidth, uint32 nHeight, ETEX_Format fmt, uint8 nTailMips)
{
u = 0;
s.nWidth = (uint16)nWidth;
s.nHeight = (uint16)nHeight;
s.fmt = fmt;
s.nTailMips = nTailMips;
}
friend bool operator < (const SStreamFormatCodeKey& a, const SStreamFormatCodeKey& b)
{
return a.u < b.u;
}
};
struct SStreamFormatSize
{
uint32 size : 31;
uint32 alignSlices : 1;
};
struct SStreamFormatCode
{
enum
{
MaxMips = 14
};
SStreamFormatSize sizes[MaxMips];
};
//////////////////////////////////////////////////////////////////////////
class CTexture
: public ITexture
, public CBaseResource
{
friend struct SDynTexture;
friend struct SDynTexture2;
friend class CD3D9Renderer;
friend struct STexStreamInState;
friend struct STexStreamOutState;
friend class ITextureStreamer;
friend class CPlanningTextureStreamer;
friend struct SPlanningTextureOrder;
friend struct SPlanningTextureRequestOrder;
friend struct STexPoolItem;
friend struct CompareStreamingPrioriry;
friend struct CompareStreamingPrioriryInv;
public:
virtual void ApplyTexture(int nTUnit, int nState = -1) override
{
Apply(nTUnit, nState);
}
virtual void Apply(int nTUnit, int nState = -1, int nTexMatSlot = EFTT_UNKNOWN, int nSUnit = -1, SResourceView::KeyType nResViewKey = SResourceView::DefaultView, EHWShaderClass eHWSC = eHWSC_Pixel);
private:
D3DSurface* m_pDeviceRTV;
D3DSurface* m_pDeviceRTVMS;
CDeviceTexture* m_pDevTexture;
const SPixFormat* m_pPixelFormat;
// Start block that should fit in one cache-line
// Reason is to minimize cache misses during texture streaming update job
// Note: This is checked COMPILE_TIME_ASSERTS in ~CTexture implementation (Texture.cpp)
STexStreamingInfo* m_pFileTexMips; // properties of the streamable texture ONLY
uint16 m_nWidth;
uint16 m_nHeight;
uint16 m_nDepth;
ETEX_Format m_eTFDst;
ETEX_TileMode m_eSrcTileMode;
uint8 m_nStreamFormatCode;
uint32 m_nFlags; // e.g. FT_USAGE_DYNAMIC
bool m_bStreamed : 1;
bool m_bStreamPrepared : 1;
bool m_bStreamRequested : 1;
bool m_bWasUnloaded : 1;
bool m_bPostponed : 1;
bool m_bForceStreamHighRes : 1;
bool m_bNeedRestoring : 1;
bool m_bNoDevTexture : 1;
bool m_bNoTexture : 1;
bool m_bResolved : 1;
bool m_bUseMultisampledRTV : 1; // Allows switching rendering between multisampled/non-multisampled rendertarget views
bool m_bHighQualityFiltering : 1;
bool m_bCustomFormat : 1; // Allow custom texture formats - for faster texture fetches
bool m_bVertexTexture : 1;
bool m_bUseDecalBorderCol : 1;
bool m_bIsSRGB : 1;
bool m_bAsyncDevTexCreation : 1;
bool m_bInDistanceSortedList : 1;
bool m_bCreatedInLevel : 1;
bool m_bUsedRecently : 1;
bool m_bStatTracked : 1;
bool m_bStreamHighPriority : 1;
uint8 m_renderTargetUseCount : CTEXTURE_RENDER_TARGET_USE_COUNT_NUMBER_BITS; // Not a bool because a render target can be pushed on the RTStack multiple times
int8 m_nCustomID;
uint8 m_nArraySize;
int8 m_nMips;
ETEX_Type m_eTT;
ETEX_Format m_eTFSrc;
int8 m_nStreamingPriority;
int8 m_nMinMipVidUploaded;
int8 m_nMinMipVidActive;
uint16 m_nStreamSlot;
int16 m_fpMinMipCur;
STexCacheFileHeader m_CacheFileHeader;
uint16 m_nDefState;
int32 m_nActualSize;
int32 m_nPersistentSize;
int m_nAccessFrameID; // last read access, compare with GetFrameID(false)
STexStreamRoundInfo m_streamRounds[MAX_PREDICTION_ZONES];
// End block that should fit in one cache-line
DynArray<STexComposition> m_composition;
float m_fCurrentMipBias; // streaming mip fading
float m_fAvgBrightness;
ColorF m_cMinColor;
ColorF m_cMaxColor;
ColorF m_cClearColor;
RenderTargetData* m_pRenderTargetData;
string m_SrcName;
#ifndef _RELEASE
string m_sAssetScopeName;
#endif
D3DShaderResourceView* m_pDeviceShaderResource;
D3DShaderResourceView* m_pDeviceShaderResourceSRGB;
typedef AZStd::function<void(uint32)> InvalidateCallbackType;
AZStd::unordered_multimap<void*, InvalidateCallbackType> m_invalidateCallbacks;
AZStd::mutex* m_invalidateCallbacksMutex = nullptr;
static StaticInstance<AZStd::mutex> m_staticInvalidateCallbacksMutex;
bool m_bisTextureMissing = false;
public:
int m_nUpdateFrameID; // last write access, compare with GetFrameID(false)
private:
#ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
struct SLowResSystemCopy
{
SLowResSystemCopy()
{
m_nLowResSystemCopyAtlasId = 0;
m_nLowResCopyWidth = m_nLowResCopyHeight = 0;
}
PodArray<ColorB> m_lowResSystemCopy;
uint16 m_nLowResCopyWidth, m_nLowResCopyHeight;
int m_nLowResSystemCopyAtlasId;
};
typedef std::map<const CTexture*, SLowResSystemCopy> LowResSystemCopyType;
static StaticInstance<LowResSystemCopyType> s_LowResSystemCopy;
void PrepareLowResSystemCopy(const byte* pTexData, bool bTexDataHasAllMips);
const ColorB* GetLowResSystemCopy(uint16& nWidth, uint16& nHeight, int** ppLowResSystemCopyAtlasId);
#endif
static CCryNameTSCRC GenName(const char* name, uint32 nFlags = 0);
static CTexture* NewTexture(const char* name, uint32 nFlags, ETEX_Format eTFDst, bool& bFound);
ETEX_Format FormatFixup(ETEX_Format src);
bool FormatFixup(STexData& td);
bool ImagePreprocessing(STexData& td);
#ifndef _RELEASE
static void OutputDebugInfo();
#endif
static CCryNameTSCRC s_sClassName;
protected:
virtual ~CTexture();
public:
//! Dirty flags will indicate what kind of device data was invalidated
enum EDeviceDirtyFlags
{
eDeviceResourceDirty = BIT(0),
eDeviceResourceViewDirty = BIT(1),
};
public:
CTexture(const uint32 nFlags)
{
m_nFlags = nFlags;
m_eTFDst = eTF_Unknown;
m_eTFSrc = eTF_Unknown;
m_nMips = 1;
m_nWidth = 0;
m_nHeight = 0;
m_eTT = eTT_2D;
m_nDepth = 1;
m_nArraySize = 1;
m_nActualSize = 0;
m_fAvgBrightness = 1.0f;
m_cMinColor = 0.0f;
m_cMaxColor = 1.0f;
m_cClearColor = ColorF(0.0f, 0.0f, 0.0f, 1.0f);
m_nPersistentSize = 0;
m_fAvgBrightness = 0.0f;
m_nUpdateFrameID = -1;
m_nAccessFrameID = -1;
m_nCustomID = -1;
m_pPixelFormat = NULL;
m_pDevTexture = NULL;
m_pDeviceRTV = NULL;
m_pDeviceRTVMS = NULL;
m_pDeviceShaderResource = NULL;
m_pDeviceShaderResourceSRGB = NULL;
m_bAsyncDevTexCreation = false;
m_renderTargetUseCount = 0;
m_bNeedRestoring = false;
m_bNoTexture = false;
m_bResolved = true;
m_bUseMultisampledRTV = true;
m_bHighQualityFiltering = false;
m_bCustomFormat = false;
m_eSrcTileMode = eTM_None;
m_bPostponed = false;
m_bForceStreamHighRes = false;
m_bWasUnloaded = false;
m_bStreamed = false;
m_bStreamPrepared = false;
m_bStreamRequested = false;
m_bVertexTexture = false;
m_bUseDecalBorderCol = false;
m_bIsSRGB = false;
m_bNoDevTexture = false;
m_bInDistanceSortedList = false;
m_bCreatedInLevel = gRenDev->m_bInLevel;
m_bUsedRecently = 0;
m_bStatTracked = 0;
m_bStreamHighPriority = 0;
m_nStreamingPriority = 0;
m_nMinMipVidUploaded = MAX_MIP_LEVELS;
m_nMinMipVidActive = MAX_MIP_LEVELS;
m_nStreamSlot = InvalidStreamSlot;
m_fpMinMipCur = MAX_MIP_LEVELS << 8;
m_nStreamFormatCode = 0;
m_nDefState = 0;
m_pFileTexMips = NULL;
m_fCurrentMipBias = 0.f;
m_pRenderTargetData = (nFlags & FT_USAGE_RENDERTARGET) ? new RenderTargetData : NULL;
COMPILE_TIME_ASSERT(MaxStreamTasks < 32767);
#if defined(USE_UNIQUE_MUTEX_PER_TEXTURE)
// Only the editor needs to use a unique mutex per texture.
// In the editor, multiple worker threads could destroy device resource sets which point to the same texture
if (gEnv->IsEditor())
{
m_invalidateCallbacksMutex = new AZStd::mutex();
}
#endif
// If we do not need a unique mutex per texture, use the StaticInstance
if (m_invalidateCallbacksMutex == nullptr)
{
m_invalidateCallbacksMutex = &m_staticInvalidateCallbacksMutex;
}
}
bool GetIsTextureMissing() const
{
return m_bisTextureMissing;
}
// ITexture interface
virtual int AddRef() { return CBaseResource::AddRef(); }
virtual int Release()
{
if (!(m_nFlags & FT_DONT_RELEASE) || IsActiveRenderTarget())
{
return CBaseResource::Release();
}
return -1;
}
virtual int ReleaseForce()
{
m_nFlags &= ~FT_DONT_RELEASE;
int nRef = 0;
while (true)
{
nRef = Release();
if (nRef <= 0)
{
break;
}
}
return nRef;
}
virtual const char* GetName() const { return GetSourceName(); }
virtual const int GetWidth() const { return m_nWidth; }
ILINE const int GetWidthNonVirtual() const { return m_nWidth; }
virtual const int GetHeight() const { return m_nHeight; }
ILINE const int GetHeightNonVirtual() const { return m_nHeight; }
virtual const int GetDepth() const { return m_nDepth; }
ILINE const int GetDepthNonVirtual() const { return m_nDepth; }
ILINE const int GetNumSides() const { return m_CacheFileHeader.m_nSides; }
ILINE const int8 GetNumPersistentMips() const { return m_CacheFileHeader.m_nMipsPersistent; }
ILINE const bool IsForceStreamHighRes() const { return m_bForceStreamHighRes; }
ILINE const bool IsStreamHighPriority() const { return m_bStreamHighPriority; }
virtual const int GetTextureID() const;
void SetFlags(uint32 nFlags) { m_nFlags = nFlags; }
virtual const uint32 GetFlags() const { return m_nFlags; }
ILINE const int GetNumMipsNonVirtual() const { return m_nMips; }
virtual const int GetNumMips() const { return m_nMips; }
virtual const int GetRequiredMip() const { return max(0, m_fpMinMipCur >> 8); }
ILINE const int GetRequiredMipNonVirtual() const { return max(0, m_fpMinMipCur >> 8); }
ILINE const int GetRequiredMipNonVirtualFP() const { return m_fpMinMipCur; }
virtual const ETEX_Type GetTextureType() const;
virtual void SetTextureType(ETEX_Type type);
ILINE const int GetDefState() const { return m_nDefState; }
virtual void SetClamp(bool bEnable)
{
int nMode = bEnable ? TADDR_CLAMP : TADDR_WRAP;
SetClampingMode(nMode, nMode, nMode);
UpdateTexStates();
}
ILINE const bool IsTextureMissing() const { return m_bisTextureMissing; }
virtual const bool IsTextureLoaded() const { return IsLoaded(); }
virtual void PrecacheAsynchronously(float fMipFactor, int nFlags, int nUpdateId, int nCounter = 1);
virtual byte* GetData32(int nSide = 0, int nLevel = 0, byte* pDst = NULL, ETEX_Format eDstFormat = eTF_R8G8B8A8);
virtual const int GetDeviceDataSize() const { return m_nActualSize; }
virtual const int GetDataSize() const
{
if (IsStreamed())
{
return StreamComputeDevDataSize(0);
}
return m_nActualSize;
}
virtual bool SetFilter(int nFilter) { return SetFilterMode(nFilter); }
virtual bool Clear();
virtual bool Clear(const ColorF& color);
virtual float GetAvgBrightness() const { return m_fAvgBrightness; }
virtual void SetAvgBrightness(float fBrightness) { m_fAvgBrightness = fBrightness; }
virtual const ColorF& GetMinColor() const { return m_cMinColor; }
virtual void SetMinColor(const ColorF& cMinColor) { m_cMinColor = cMinColor; }
virtual const ColorF& GetMaxColor() const { return m_cMaxColor; }
virtual void SetMaxColor(const ColorF& cMaxColor) { m_cMaxColor = cMaxColor; }
virtual const ColorF& GetClearColor() const override { return m_cClearColor; }
virtual void SetClearColor(const ColorF& cClearColor) { m_cClearColor = cClearColor; }
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
virtual const char* GetFormatName() const;
virtual const char* GetTypeName() const;
virtual const bool IsShared() const
{
return CBaseResource::GetRefCounter() > 1;
}
virtual const ETEX_Format GetTextureDstFormat() const { return m_eTFDst; }
virtual const ETEX_Format GetTextureSrcFormat() const { return m_eTFSrc; }
virtual const bool IsParticularMipStreamed(float fMipFactor) const;
// Internal functions
const ETEX_Format GetDstFormat() const override { return m_eTFDst; }
const ETEX_Format GetSrcFormat() const override { return m_eTFSrc; }
const ETEX_Type GetTexType() const { return m_eTT; }
const uint32 StreamGetNumSlices() const
{
switch (m_eTT)
{
case eTT_2D:
case eTT_2DArray:
return m_nArraySize;
case eTT_Cube:
return 6 * m_nArraySize;
default:
#ifndef _RELEASE
__debugbreak();
#endif
return 1;
}
}
void RT_ReleaseDevice();
static _inline bool IsTextureExist(const ITexture* pTex) { return pTex && pTex->GetDevTexture(); }
const bool IsNoTexture() const { return m_bNoTexture; };
void SetNeedRestoring() { m_bNeedRestoring = true; }
void SetWasUnload(bool bSet) { m_bWasUnloaded = bSet; }
const bool IsPartiallyLoaded() const { return m_nMinMipVidUploaded != 0; }
const bool IsUnloaded(void) const { return m_bWasUnloaded; }
void SetKeepSystemCopy(bool bKeepSystemCopy)
{
if (bKeepSystemCopy)
{
m_nFlags |= FT_KEEP_LOWRES_SYSCOPY;
}
else
{
m_nFlags &= ~FT_KEEP_LOWRES_SYSCOPY;
}
}
void SetStreamingInProgress(uint16 nStreamSlot)
{
assert (nStreamSlot == InvalidStreamSlot || m_nStreamSlot == InvalidStreamSlot);
m_nStreamSlot = nStreamSlot;
}
void SetStreamingPriority(const uint8 nPriority) { m_nStreamingPriority = nPriority; }
ILINE const STexStreamRoundInfo& GetStreamRoundInfo(int zone) const { return m_streamRounds[zone]; }
void ResetNeedRestoring() { m_bNeedRestoring = false; }
const bool IsNeedRestoring() const { return m_bNeedRestoring; }
const int StreamGetLoadedMip() const { return m_nMinMipVidUploaded; }
const uint8 StreamGetFormatCode() const { return m_nStreamFormatCode; }
const int StreamGetActiveMip() const { return m_nMinMipVidActive; }
const int StreamGetPriority() const { return m_nStreamingPriority; }
const bool IsResolved() const { return m_bResolved; }
void SetUseMultisampledRTV(bool bSet) { m_bUseMultisampledRTV = bSet; }
const bool UseMultisampledRTV() const { return m_bUseMultisampledRTV; }
const bool IsVertexTexture() const { return m_bVertexTexture; }
void SetVertexTexture(bool bEnable) { m_bVertexTexture = bEnable; }
const bool IsDynamic() const { return ((m_nFlags & (FT_USAGE_DYNAMIC | FT_USAGE_RENDERTARGET)) != 0); }
bool IsStillUsedByGPU();
// Render targets can be bound for write on the render target stack multiple times at once,
// so increment and decrement when it is pushed/popped from the stack
void IncrementRenderTargetUseCount()
{
assert(m_renderTargetUseCount < (1 << CTEXTURE_RENDER_TARGET_USE_COUNT_NUMBER_BITS));
m_renderTargetUseCount++;
}
void DecrementRenderTargetUseCount()
{
assert(m_renderTargetUseCount > 0);
m_renderTargetUseCount--;
}
// Is this texture bound on the render target stack?
const bool IsActiveRenderTarget() const { return m_renderTargetUseCount > 0; }
const bool IsLoaded() const { return (m_nFlags & FT_FAILED) == 0; }
ILINE const bool IsStreamed() const { return m_bStreamed; }
ILINE const bool IsInDistanceSortedList() const { return m_bInDistanceSortedList; }
bool IsPostponed() const { return m_bPostponed; }
ILINE const bool IsStreaming() const { return m_nStreamSlot != InvalidStreamSlot; }
virtual const bool IsStreamedVirtual() const { return IsStreamed(); }
virtual bool IsStreamedIn(const int nMinPrecacheRoundIds[MAX_STREAM_PREDICTION_ZONES]) const;
virtual const int GetAccessFrameId() const { return m_nAccessFrameID; }
ILINE const int GetAccessFrameIdNonVirtual() const { return m_nAccessFrameID; }
void SetResolved(bool bResolved) { m_bResolved = bResolved; }
const int GetCustomID() const { return m_nCustomID; }
void SetCustomID(int nID) { m_nCustomID = nID; }
const bool UseDecalBorderCol() const { return m_bUseDecalBorderCol; }
const bool IsSRGB() const { return m_bIsSRGB; }
void SRGBRead(bool bEnable = false) { m_bIsSRGB = bEnable; }
const bool IsCustomFormat() const { return m_bCustomFormat; }
void SetCustomFormat() { m_bCustomFormat = true; }
void SetWidth(short width) { m_nWidth = width; }
void SetHeight(short height) { m_nHeight = height; }
int GetUpdateFrameID() const { return m_nUpdateFrameID; }
ILINE const int32 GetActualSize() const { return m_nActualSize; }
ILINE const int32 GetPersistentSize() const { return m_nPersistentSize; }
ILINE void PrefetchStreamingInfo() const { PrefetchLine(m_pFileTexMips, 0); }
const STexStreamingInfo* GetStreamingInfo() const { return m_pFileTexMips; }
virtual const bool IsStreamable() const { return IsStreamed(); }
void Readback(AZ::u32 subresourceIndex, StagingHook callback) override;
const bool IsStreamableNonVirtual() const { return !(m_nFlags & FT_DONT_STREAM) && !(m_eTT == eTT_3D); }
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION TEXTURE_H_SECTION_5
#include AZ_RESTRICTED_FILE(Texture_h)
#endif
bool IsFPFormat() const { return CImageExtensionHelper::IsRangeless(m_eTFDst); };
D3DSurface* GetDeviceRT() const { return m_pDeviceRTV; }
CDeviceTexture* GetDevTexture() const { return m_pDevTexture; }
void SetDevTexture(CDeviceTexture* pDeviceTex);
bool IsAsyncDevTexCreation() const { return m_bAsyncDevTexCreation; }
// note: render target should be created with FT_FORCE_MIPS flag
bool GenerateMipMaps(bool bSetOrthoProj = false, bool bUseHW = true, bool bNormalMap = false);
D3DShaderResourceView* GetShaderResourceView(SResourceView::KeyType resourceViewID = SResourceView::DefaultView, bool bLegacySrgbLookup = false);
void SetShaderResourceView(D3DShaderResourceView* pDeviceShaderResource, bool bMultisampled = false);
CDeviceTexture* GetDevTextureMSAA() const { return m_pRenderTargetData->m_pDeviceTextureMSAA; }
D3DUnorderedAccessView* GetDeviceUAV();
SResourceView& GetResourceView(const SResourceView& rvDesc);
void* CreateDeviceResourceView(const SResourceView& rvDesc);
D3DDepthSurface* GetDeviceDepthStencilSurf(int nFirstSlice = 0, int nSliceCount = -1);
#ifndef NULL_RENDERER
D3DSurface* GetSurface(int nCMSide, int nLevel);
#endif
const SPixFormat* GetPixelFormat() const { return m_pPixelFormat; }
bool Invalidate(int nNewWidth, int nNewHeight, ETEX_Format eTF);
const char* GetSourceName() const { return m_SrcName.c_str(); }
void SetSourceName( const char* srcName) { m_SrcName = srcName; }
const int GetSize(bool bIncludePool) const;
void PostCreate();
//////////////////////////////////////////////////////////////////////////
// Will notify resource's user that some data of the the resource was invalidated.
// dirtyFlags - one or more of the EDeviceDirtyFlags enum bits
void InvalidateDeviceResource(uint32 dirtyFlags);
void AddInvalidateCallback(void* listener, InvalidateCallbackType callback);
void RemoveInvalidateCallbacks(void* listener);
//////////////////////////////////////////////////////////////////////////
public:
//===================================================================
// Streaming support
// Global streaming constants
static int s_nStreamingMode;
static int s_nStreamingUpdateMode;
static int s_nStreamingThroughput; // in bytes
static float s_nStreamingTotalTime; // in secs
static bool s_bStreamDontKeepSystem;
static bool s_bPrecachePhase;
static bool s_bInLevelPhase;
static bool s_bPrestreamPhase;
static bool s_bStreamingFromHDD;
static int s_nTexturesDataBytesLoaded;
static volatile int s_nTexturesDataBytesUploaded;
static int s_nStatsAllocFails;
static bool s_bOutOfMemoryTotally;
static volatile size_t s_nStatsStreamPoolInUseMem; // Amount of stream pool currently in use by texture streaming
static volatile size_t s_nStatsStreamPoolBoundMem; // Amount of stream pool currently bound and in use by textures (avail + non avail)
static volatile size_t s_nStatsStreamPoolBoundPersMem; // Amount of stream pool currently bound and in use by persistent texture mem (avail + non avail)
static AZStd::atomic_uint s_nStatsCurManagedNonStreamedTexMem;
static AZStd::atomic_uint s_nStatsCurDynamicTexMem;
static volatile size_t s_nStatsStreamPoolWanted;
static bool s_bStatsComputeStreamPoolWanted;
struct WantedStat
{
_smart_ptr<ITexture> pTex;
uint32 nWanted;
};
static std::vector<WantedStat>* s_pStatsTexWantedLists;
static AZStd::set<string, AZStd::less<string>, AZ::StdLegacyAllocator> s_vTexReloadRequests;
static CryCriticalSection s_xTexReloadLock;
static CTextureStreamPoolMgr* s_pPoolMgr;
static ITextureStreamer* s_pTextureStreamer;
static CryCriticalSection s_streamFormatLock;
static SStreamFormatCode s_formatCodes[256];
static uint32 s_nFormatCodes;
typedef std::map<SStreamFormatCodeKey, uint32> TStreamFormatCodeKeyMap;
static StaticInstance<TStreamFormatCodeKeyMap> s_formatCodeMap;
static const int LOW_SPEC_PC;
static const int MEDIUM_SPEC_PC;
static const int HIGH_SPEC_PC;
static const int VERYHIGH_SPEC_PC;
enum
{
MaxStreamTasks = 512,
MaxStreamPrepTasks = 8192,
StreamOutMask = 0x8000,
StreamPrepMask = 0x4000,
StreamIdxMask = 0x4000 - 1,
InvalidStreamSlot = 0xffff,
};
static CTextureArrayAlloc<STexStreamInState, MaxStreamTasks> s_StreamInTasks;
static CTextureArrayAlloc<STexStreamPrepState*, MaxStreamPrepTasks> s_StreamPrepTasks;
#ifdef TEXSTRM_ASYNC_TEXCOPY
static CTextureArrayAlloc<STexStreamOutState, MaxStreamTasks> s_StreamOutTasks;
#endif
static volatile TIntAtomic s_nBytesSubmittedToStreaming;
static volatile TIntAtomic s_nMipsSubmittedToStreaming;
static int s_nBytesRequiredNotSubmitted;
#if !defined (_RELEASE)
static int s_TextureUpdates;
static float s_TextureUpdatesTime;
static int s_TexturesUpdatedRendered;
static float s_TextureUpdatedRenderedTime;
static int s_StreamingRequestsCount;
static float s_StreamingRequestsTime;
static int s_nStatsCurManagedStreamedTexMemRequired;
#endif
#ifdef ENABLE_TEXTURE_STREAM_LISTENER
static ITextureStreamListener* s_pStreamListener;
#endif
static void Precache();
static void RT_Precache();
static void StreamValidateTexSize();
static uint8 StreamComputeFormatCode(uint32 nWidth, uint32 nHeight, uint32 nMips, ETEX_Format fmt);
#ifdef ENABLE_TEXTURE_STREAM_LISTENER
static void StreamUpdateStats();
#endif
#if defined(TEXSTRM_STORE_DEVSIZES)
int StreamComputeDevDataSize(int nFromMip) const
{
if (m_pFileTexMips)
{
return m_pFileTexMips->m_pMipHeader[nFromMip].m_DevSideSizeWithMips;
}
else
{
return CDeviceTexture::TextureDataSize(
max(1, m_nWidth >> nFromMip),
max(1, m_nHeight >> nFromMip),
max(1, m_nDepth >> nFromMip),
m_nMips - nFromMip,
StreamGetNumSlices(),
m_eTFDst);
}
}
#else
int StreamComputeDevDataSize(int nFromMip) const
{
return CDeviceTexture::TextureDataSize(
max(1, m_nWidth >> nFromMip),
max(1, m_nHeight >> nFromMip),
max(1, m_nDepth >> nFromMip),
m_nMips - nFromMip,
StreamGetNumSlices(),
m_eTFDst);
}
#endif
#ifndef NULL_RENDERER
void StreamUploadMip(IReadStream* pStream, int nMip, int nBaseMipOffset, STexPoolItem* pNewPoolItem, STexStreamInMipState& mipState);
void StreamUploadMipSide(
int const iSide, int const Sides, const byte* const pRawData, int nSrcPitch,
const STexMipHeader& mh, bool const bStreamInPlace,
int const nCurMipWidth, int const nCurMipHeight, int const nMip,
CDeviceTexture* pDeviceTexture, uint32 nBaseTexWidth, uint32 nBaseTexHeight, int nBaseMipOffset);
#endif
void StreamExpandMip(const void* pRawData, int nMip, int nBaseMipOffset, int nSideDelta);
static void RT_FlushAllStreamingTasks(const bool bAbort = false);
static bool IsStreamingInProgress() { return s_StreamInTasks.GetNumLive() > 0; }
static void AbortStreamingTasks(CTexture* pTex);
static bool StartStreaming(CTexture* pTex, STexPoolItem* pNewPoolItem, const int nStartMip, const int nEndMip, const int nActivateMip, EStreamTaskPriority estp);
bool CanStreamInPlace(int nMip, STexPoolItem* pNewPoolItem);
#if defined(TEXSTRM_ASYNC_TEXCOPY)
bool CanAsyncCopy();
#endif
void StreamCopyMipsTexToMem(int nStartMip, int nEndMip, bool bToDevice, STexPoolItem* pNewPoolItem);
static void StreamCopyMipsTexToTex(STexPoolItem* pSrcItem, int nMipSrc, STexPoolItem* pDestItem, int nMipDest, int nNumMips); // GPU-assisted platform-dependent
static void CopySliceChain(CDeviceTexture* const pDevTexture, int ownerMips, int nDstSlice, int nDstMip, CDeviceTexture* pSrcDevTex, int nSrcSlice, int nSrcMip, int nSrcMips, int nNumMips);
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION TEXTURE_H_SECTION_6
#include AZ_RESTRICTED_FILE(Texture_h)
#endif
#if defined(TEXSTRM_DEFERRED_UPLOAD)
ID3D11CommandList* StreamCreateDeferred(int nStartMip, int nEndMip, STexPoolItem* pNewPoolItem, STexPoolItem* pSrcPoolItem);
void StreamApplyDeferred(ID3D11CommandList* pCmdList);
#endif
void StreamReleaseMipsData(int nStartMip, int nEndMip);
int16 StreamCalculateMipsSignedFP(float fMipFactor) const;
float StreamCalculateMipFactor(int16 nMipsSigned) const;
virtual int StreamCalculateMipsSigned(float fMipFactor) const;
virtual int GetStreamableMipNumber() const;
virtual int GetStreamableMemoryUsage(int nStartMip) const;
virtual int GetMinLoadedMip() const { return m_nMinMipVidUploaded; }
void SetMinLoadedMip(int nMinMip);
void StreamUploadMips(int nStartMip, int nEndMip, STexPoolItem* pNewPoolItem);
int StreamUnload();
int StreamTrim(int nToMip);
void StreamActivateLod(int nMinMip);
void StreamLoadFromCache(const int nFlags);
bool StreamPrepare(bool bFromLoad);
bool StreamPrepare(CImageFile* pImage);
bool StreamPrepareComposition();
bool StreamPrepare_Platform();
bool StreamPrepare_Finalise(bool bFromLoad);
STexPool* StreamGetPool(int nStartMip, int nMips);
STexPoolItem* StreamGetPoolItem(int nStartMip, int nMips, bool bShouldBeCreated, bool bCreateFromMipData = false, bool bCanCreate = true, bool bForStreamOut = false);
void StreamRemoveFromPool();
void StreamAssignPoolItem(STexPoolItem* pItem, int nMinMip);
static void StreamState_Update();
static void StreamState_UpdatePrep();
static STexStreamInState* StreamState_AllocateIn();
static void StreamState_ReleaseIn(STexStreamInState* pState);
#ifdef TEXSTRM_ASYNC_TEXCOPY
static STexStreamOutState* StreamState_AllocateOut();
static void StreamState_ReleaseOut(STexStreamOutState* pState);
#endif
static STexStreamingInfo* StreamState_AllocateInfo(int nMips);
static void StreamState_ReleaseInfo(CTexture* pOwnerTex, STexStreamingInfo* pInfo);
ILINE void Relink()
{
gRenDev->m_pRT->RC_RelinkTexture(this);
}
ILINE void Unlink()
{
gRenDev->m_pRT->RC_UnlinkTexture(this);
}
_inline void RT_Relink()
{
if (!IsStreamed() || IsInDistanceSortedList())
{
return;
}
s_pTextureStreamer->Relink(this);
}
_inline void RT_Unlink()
{
if (IsInDistanceSortedList())
{
s_pTextureStreamer->Unlink(this);
}
}
//=======================================================
static void ApplyForID(int nTUnit, int nID, int nState, int nSUnit)
{
CTexture* pTex = GetByID(nID);
assert (pTex);
if (pTex)
{
pTex->Apply(nTUnit, nState, EFTT_UNKNOWN, nSUnit);
}
}
static void ApplyForID(int nID, int nTUnit, int nTState, int nTexMaterialSlot, int nSUnit, bool useWhiteDefault);
static const CCryNameTSCRC& mfGetClassName();
static CTexture* GetByID(int nID);
static CTexture* GetByName(const char* szName, uint32 flags = 0);
static CTexture* GetByNameCRC(CCryNameTSCRC Name);
static CTexture* ForName(const char* name, uint32 nFlags, ETEX_Format eTFDst);
static CTexture* CreateTextureArray(const char* name, ETEX_Type eType, uint32 nWidth, uint32 nHeight, uint32 nArraySize, int nMips, uint32 nFlags, ETEX_Format eTF, int nCustomID = -1);
static CTexture* CreateTextureObject(const char* name, uint32 nWidth, uint32 nHeight, int nDepth, ETEX_Type eTT, uint32 nFlags, ETEX_Format eTF, int nCustomID = -1);
// Methods exposed to external libraries
static CTexture* CreateRenderTarget(const char* name, uint32 nWidth, uint32 nHeight, const ColorF& cClear, ETEX_Type eTT, uint32 nFlags, ETEX_Format eTF, int nCustomID = -1);
static void ApplyDepthTextureState(int unit, int nFilter, bool clamp);
static CTexture* GetZTargetTexture();
static int GetTextureState(const STexState& TS);
static uint32 TextureDataSize(uint32 nWidth, uint32 nHeight, uint32 nDepth, uint32 nMips, uint32 nSlices, const ETEX_Format eTF, ETEX_TileMode eTM = eTM_None);
static void InitStreaming();
static void InitStreamingDev();
static void Init();
static void PostInit();
static void RT_FlushStreaming(bool bAbort);
static void ShutDown();
static void CreateSystemTargets();
static void ReleaseSystemTargets();
static void ReleaseMiscTargets();
static void ReleaseSystemTextures();
static void LoadDefaultSystemTextures();
static bool ReloadFile(const char* szFileName);
static bool ReloadFile_Request(const char* szFileName);
static void ReloadTextures();
static CTexture* Create2DTexture(const char* szName, int nWidth, int nHeight, int nMips, int nFlags, const byte* pData, ETEX_Format eTFSrc, ETEX_Format eTFDst, bool bAsyncDevTexCreation = false);
static CTexture* Create3DTexture(const char* szName, int nWidth, int nHeight, int nDepth, int nMips, int nFlags, const byte* pData, ETEX_Format eTFSrc, ETEX_Format eTFDst);
static CTexture* Create2DCompositeTexture(const char* szName, int nWidth, int nHeight, int nMips, int nFlags, ETEX_Format eTFDst, const STexComposition* pCompositions, size_t nCompositions);
static void Update();
static void RT_LoadingUpdate();
static void RLT_LoadingUpdate();
// Loading/creating functions
bool Load(ETEX_Format eTFDst);
bool Load(CImageFile* pImage);
bool LoadFromImage(const char* name, ETEX_Format eTFDst = eTF_Unknown);
virtual bool Reload();
bool ToggleStreaming(const bool bEnable);
bool CreateTexture(STexData& td);
byte* GetSubImageData32(int nX, int nY, int nW, int nH, int& nOutTexDim);
// API depended functions
void Unbind();
bool Resolve(int nTarget = 0, bool bUseViewportSize = false);
bool CreateDeviceTexture(const byte* pData[6]);
bool RT_CreateDeviceTexture(const byte* pData[6]);
bool CreateRenderTarget(ETEX_Format eTF, const ColorF& cClear);
void ReleaseDeviceTexture(bool bKeepLastMips, bool bFromUnload = false);
void ApplySamplerState(int nSUnit, EHWShaderClass eHWSC = eHWSC_Pixel, int nState = -1);
void ApplyTexture(int nTUnit, EHWShaderClass eHWSC = eHWSC_Pixel, SResourceView::KeyType nResViewKey = SResourceView::DefaultView);
ETEX_Format ClosestFormatSupported(ETEX_Format eTFDst);
static ETEX_Format ClosestFormatSupported(ETEX_Format eTFDst, const SPixFormat*& pPF);
void SetTexStates();
void UpdateTexStates();
bool SetFilterMode(int nFilter);
bool SetClampingMode(int nAddressU, int nAddressV, int nAddressW);
void UpdateTextureRegion(const uint8_t* data, int nX, int nY, int nZ, int USize, int VSize, int ZSize, ETEX_Format eTFSrc);
void RT_UpdateTextureRegion(const byte* data, int nX, int nY, int nZ, int USize, int VSize, int ZSize, ETEX_Format eTFSrc);
// Create2DTextureWithMips is similar to Create2DTexture, but it also propagates the mip argument correctly.
// The original Create2DTexture function force sets mips to 1.
// This has been separated from Create2DTexture to ensure that we preserve backwards compatibility.
bool Create2DTextureWithMips(int nWidth, int nHeight, int nMips, int nFlags, const byte* pData, ETEX_Format eTFSrc, ETEX_Format eTFDst);
bool Create2DTexture(int nWidth, int nHeight, int nMips, int nFlags, const byte* pData, ETEX_Format eTFSrc, ETEX_Format eTFDst);
bool Create3DTexture(int nWidth, int nHeight, int nDepth, int nMips, int nFlags, const byte* pData, ETEX_Format eTFSrc, ETEX_Format eTFDst);
bool SetNoTexture( const CTexture* pDefaultTexture );
bool IsMSAAChanged();
static byte* Convert(const byte* srcData, int width, int height, int srcMipCount, ETEX_Format srcFormat, ETEX_Format dstFormat, int& outSize, bool bLinear);
static void SetSamplerState(int nTS, int nSSlot, EHWShaderClass eHWSC = eHWSC_Pixel);
// Helper functions
static bool IsFormatSupported(ETEX_Format eTFDst);
static void GenerateZMaps();
static void DestroyZMaps();
static void GenerateHDRMaps();
// allocate or deallocate star maps
static void DestroyHDRMaps();
static void GenerateSceneMap(ETEX_Format eTF);
static void DestroySceneMap();
static void GenerateCachedShadowMaps();
static void DestroyCachedShadowMaps();
static void GenerateNearestShadowMap();
static void DestroyNearestShadowMap();
static ILINE Vec2i GetBlockDim(const ETEX_Format eTF)
{
return CImageExtensionHelper::GetBlockDim(eTF);
}
static int CalcNumMips(int nWidth, int nHeight);
// upload mip data from file regarding to platform specifics
static bool IsInPlaceFormat(const ETEX_Format fmt);
static void ExpandMipFromFile(byte* dest, const int destSize, const byte* src, const int srcSize, const ETEX_Format fmt);
static ILINE bool IsBlockCompressed(const ETEX_Format eTF) { return CImageExtensionHelper::IsBlockCompressed(eTF); }
static ILINE int BytesPerBlock(ETEX_Format eTF) { return CImageExtensionHelper::BytesPerBlock(eTF); }
static const char* NameForTextureFormat(ETEX_Format eTF) { return CImageExtensionHelper::NameForTextureFormat(eTF); }
static const char* NameForTextureType(ETEX_Type eTT) { return CImageExtensionHelper::NameForTextureType(eTT); }
static ETEX_Format TextureFormatForName(const char* str) { return CImageExtensionHelper::TextureFormatForName(str); }
static ETEX_Type TextureTypeForName(const char* str) { return CImageExtensionHelper::TextureTypeForName(str); }
static bool IsDeviceFormatTypeless(D3DFormat nFormat);
static bool IsDeviceFormatSRGBReadable(D3DFormat nFormat);
static D3DFormat DeviceFormatFromTexFormat(ETEX_Format eTF);
static ETEX_Format TexFormatFromDeviceFormat(D3DFormat nFormat);
static D3DFormat GetD3DLinFormat(D3DFormat nFormat);
static D3DFormat ConvertToDepthStencilFmt(D3DFormat nFormat);
static D3DFormat ConvertToStencilFmt(D3DFormat nFormat);
static D3DFormat ConvertToShaderResourceFmt(D3DFormat nFormat);
static D3DFormat ConvertToSRGBFmt(D3DFormat fmt);
static D3DFormat ConvertToSignedFmt(D3DFormat fmt);
static D3DFormat ConvertToTypelessFmt(D3DFormat fmt);
static SEnvTexture* FindSuitableEnvTex(Vec3& Pos, Ang3& Angs, bool bMustExist, int RendFlags, bool bUseExistingREs, CShader* pSH, CShaderResources* pRes, CRenderObject* pObj, bool bReflect, IRenderElement* pRE, bool* bMustUpdate);
static bool RenderEnvironmentCMHDR(int size, Vec3& Pos, TArray<unsigned short>& vecData);
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
static bool RenderToTexture(int handle, const CCamera& camera, AzRTT::RenderContextId contextId);
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
static void DrawCubeSide(Vec3& Pos, int tex_size, int side, float fMaxDist);
static void DrawSceneToCubeSide(Vec3& Pos, int tex_size, int side);
static void GetAverageColor(SEnvTexture* cm, int nSide);
public:
static AZStd::vector<STexState, AZ::StdLegacyAllocator> s_TexStates;
static int GetTexState(const STexState& TS)
{
uint32 i;
const uint32 nTexStatesSize = s_TexStates.size();
for (i = 0; i < nTexStatesSize; i++)
{
STexState* pTS = &s_TexStates[i];
if (*pTS == TS)
{
break;
}
}
if (i == nTexStatesSize)
{
s_TexStates.push_back(TS);
s_TexStates[i].PostCreate();
}
return i;
}
static void ComputeRootedTexturePath(const char* sourcePath, char* destPath, size_t destPathLength);
static bool m_bLoadedSystem;
static STexState s_sDefState;
static STexStageInfo s_TexStages[MAX_TMU];
static uint32 s_TexState_MipSRGBMask[MAX_TMU];
static ETEX_Format s_eTFZ;
// ==============================================================================
static CTexture* s_ptexMipColors_Diffuse;
static CTexture* s_ptexMipColors_Bump;
static CTexture* s_ptexFromRE[8];
static CTexture* s_ptexShadowID[8];
static CTexture* s_ptexShadowMask;
static CTexture* s_ptexFromRE_FromContainer[2];
static CTexture* s_ptexFromObj;
static CTexture* s_ptexSvoTree;
static CTexture* s_ptexSvoTris;
static CTexture* s_ptexSvoGlobalCM;
static CTexture* s_ptexSvoRgbs;
static CTexture* s_ptexSvoNorm;
static CTexture* s_ptexSvoOpac;
static CTexture* s_ptexFromObjCM;
static CTexture* s_ptexRT_2D;
static CTexture* s_ptexCachedShadowMap[MAX_GSM_LODS_NUM];
static CTexture* s_ptexNearestShadowMap;
static CTexture* s_ptexHeightMapAO[2];
static CTexture* s_ptexHeightMapAODepth[2];
static CTexture* s_ptexSceneNormalsMap; // RT with normals for deferred shading
static CTexture* s_ptexSceneNormalsMapMS; // Dummy normals target for binding multisampled rt
static CTexture* s_ptexSceneNormalsBent;
static CTexture* s_ptexAOColorBleed;
static CTexture* s_ptexSceneDiffuse;
static CTexture* s_ptexSceneSpecular;
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION TEXTURE_H_SECTION_7
#include AZ_RESTRICTED_FILE(Texture_h)
#endif
static CTexture* s_ptexAmbientLookup;
static CTexture* s_ptexBackBuffer; // back buffer copy
static CTexture* s_ptexModelHudBuffer; // used by Menu3DModelRenderer to postprocess render models
static CTexture* s_ptexPrevBackBuffer[2][2]; // previous frame back buffer copies (for left and right eye)
static CTexture* s_ptexCached3DHud; // 3d hud cached overframes
static CTexture* s_ptexCached3DHudScaled; // downsampled 3d hud cached overframes
static CTexture* s_ptexBackBufferScaled[3]; // backbuffer low-resolution/blurred version. 2x/4x/8x/16x smaller than screen
static CTexture* s_ptexBackBufferScaledTemp[2]; // backbuffer low-resolution/blurred version. 2x/4x/8x/16x smaller than screen, temp textures (used for blurring/ping-pong)
static CTexture* s_ptexPrevFrameScaled; // 2x
static CTexture* s_ptexDepthBufferQuarter; //Quater res depth buffer
static CTexture* s_ptexWaterOcean; // water ocean vertex texture
static CTexture* s_ptexWaterVolumeDDN; // water volume heightmap
static CTexture* s_ptexWaterVolumeTemp; // water volume heightmap
static CTexture* s_ptexWaterRipplesDDN; // xy: wave propagation normals, z: frame t-2, w: frame t-1
static CTexture* s_ptexWaterVolumeRefl[2]; // water volume reflections buffer
static CTexture* s_ptexWaterCaustics[2]; // caustics buffers
static CTexture* s_ptexRainOcclusion; // top-down rain occlusion
static CTexture* s_ptexRainSSOcclusion[2]; // screen-space rain occlusion accumulation
static CTexture* s_ptexRainDropsRT[2];
static CTexture* s_ptexRT_ShadowPool;
static CTexture* s_ptexRT_ShadowStub;
static CTexture* s_ptexCloudsLM;
static CTexture* s_ptexSceneTarget; // Shared rt for generic usage (refraction/srgb/diffuse accumulation/hdr motionblur/etc)
static CTexture* s_ptexCurrSceneTarget; // Pointer to current scene target, mostly for reading from destination rt
static CTexture* s_ptexSceneTargetR11G11B10F[2];
static CTexture* s_ptexSceneTargetScaledR11G11B10F[4];
static CTexture* s_ptexSceneCoCHistory[2];
static CTexture* s_ptexCurrentSceneDiffuseAccMap;
static CTexture* s_ptexSceneDiffuseAccMap;
static CTexture* s_ptexSceneSpecularAccMap;
static CTexture* s_ptexSceneTexturesMap;
static CTexture* s_ptexSceneDiffuseAccMapMS;
static CTexture* s_ptexSceneSpecularAccMapMS;
static CTexture* s_ptexZTarget;
static CTexture* s_ptexZTargetDownSample[4];
static CTexture* s_ptexZTargetScaled;
static CTexture* s_ptexZTargetScaled2;
static CTexture* s_ptexHDRTarget;
static CTexture* s_ptexVelocityObjects[2]; // Dynamic object velocity (for left and right eye)
static CTexture* s_ptexVelocity;
static CTexture* s_ptexVelocityTiles[3];
// Intermediate textures used for fur rendering
static CTexture* s_ptexFurZTarget; // Z target with outermost shell stipples. s_ptexZTarget has the stipples blurred out
static CTexture* s_ptexFurLightAcc; // Lighting accumulation after deferred shading
static CTexture* s_ptexFurPrepass; // Packed diffuse, specular, and depth for shell passes
// Confetti Begin: David Srour
// Dedicated stencil & linear depth buffer for GMEM render path.
static CTexture* s_ptexGmemStenLinDepth;
// Confetti End
static CTexture* s_ptexHDRTargetPrev;
static CTexture* s_ptexHDRTargetScaled[4];
static CTexture* s_ptexHDRTargetScaledTmp[4];
static CTexture* s_ptexHDRTargetScaledTempRT[4];
static CTexture* s_ptexHDRDofLayers[2];
static CTexture* s_ptexSceneCoC[MIN_DOF_COC_K];
static CTexture* s_ptexSceneCoCTemp;
static CTexture* s_ptexHDRTempBloom[2];
static CTexture* s_ptexHDRFinalBloom;
static CTexture* s_ptexHDRAdaptedLuminanceCur[8];
static int s_nCurLumTextureIndex;
static CTexture* s_ptexCurLumTexture;
static CTexture* s_ptexHDRToneMaps[NUM_HDR_TONEMAP_TEXTURES];
static CTexture* s_ptexHDRMeasuredLuminance[MAX_GPU_NUM];
static CTexture* s_ptexHDRMeasuredLuminanceDummy;
static CTexture* s_ptexSkyDomeMie;
static CTexture* s_ptexSkyDomeRayleigh;
static CTexture* s_ptexSkyDomeMoon;
static CTexture* s_ptexSceneTargetScaled;
static CTexture* s_ptexSceneTargetScaledBlurred;
static CTexture* s_ptexVolObj_Density;
static CTexture* s_ptexVolObj_Shadow;
static CTexture* s_ptexColorChart;
static CTexture* s_ptexStereoL;
static CTexture* s_ptexStereoR;
static CTexture* s_ptexFlaresOcclusionRing[MAX_OCCLUSION_READBACK_TEXTURES];
static CTexture* s_ptexFlaresGather;
static CTexture* s_ptexDepthStencilRemapped;
static SEnvTexture s_EnvCMaps[MAX_ENVCUBEMAPS];
static SEnvTexture s_EnvTexts[MAX_ENVTEXTURES];
static StaticInstance<TArray<SEnvTexture>> s_CustomRT_2D;
static StaticInstance<TArray<CTexture>> s_ShaderTemplates; // [Shader System TO DO] bad design - change (or shoot)
static bool s_ShaderTemplatesInitialized;
static CTexture* s_pTexNULL;
static CTexture* s_pBackBuffer;
static CTexture* s_FrontBufferTextures[2];
static CTexture* s_ptexVolumetricFog;
static CTexture* s_ptexVolumetricFogDensityColor;
static CTexture* s_ptexVolumetricFogDensity;
static CTexture* s_ptexVolumetricClipVolumeStencil;
#if defined(VOLUMETRIC_FOG_SHADOWS)
static CTexture* s_ptexVolFogShadowBuf[2];
#endif
#if defined(TEXSTRM_DEFERRED_UPLOAD)
static ID3D11DeviceContext* s_pStreamDeferredCtx;
#endif
static CTexture* s_defaultEnvironmentProbeDummy;
void* operator new(size_t sz)
{
return CryModuleMemalign(sz, std::alignment_of<CTexture>::value);
}
void operator delete(void* ptr)
{
CryModuleMemalignFree(ptr);
}
} _ALIGN(128);
////////////////////////////////////////////////////////////////
class CTexAnim : public ITexAnim
{
friend class CShaderMan;
friend struct SCGTexture;
friend struct STexSamplerRT;
public:
CTexAnim();
~CTexAnim();
AZ_DISABLE_COPY_MOVE(CTexAnim)
void Release() override;
void AddRef() override;
int Size() const;
private:
int m_nRefCount;
TArray<CTexture*> m_TexPics;
int m_Rand;
int m_NumAnimTexs;
bool m_bLoop;
float m_Time;
};
bool WriteTGA(const byte* dat, int wdt, int hgt, const char* name, int src_bits_per_pixel, int dest_bits_per_pixel);
bool WriteJPG(const byte* dat, int wdt, int hgt, const char* name, int bpp, int nQuality = 100);
#if defined(WIN32) || defined(WIN64)
byte* WriteDDS(const byte* dat, int wdt, int hgt, int dpth, const char* name, ETEX_Format eTF, int nMips, ETEX_Type eTT, bool bToMemory = false, int* nSize = NULL);
#endif