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.
3459 lines
114 KiB
C++
3459 lines
114 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.
|
|
|
|
// Description : Common texture manager implementation.
|
|
|
|
|
|
#include "RenderDll_precompiled.h"
|
|
#include <CryPath.h>
|
|
#include <ImageExtensionHelper.h>
|
|
#include "Image/CImage.h"
|
|
#include "Image/DDSImage.h"
|
|
#include "TextureManager.h"
|
|
#include <IResourceManager.h>
|
|
#include "I3DEngine.h"
|
|
#include <Pak/CryPakUtils.h>
|
|
#include "StringUtils.h" // stristr()
|
|
#include "TextureManager.h"
|
|
#include "TextureStreamPool.h"
|
|
#include "TextureHelpers.h"
|
|
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
|
|
#include "StereoTexture.h"
|
|
#include <AzCore/Debug/AssetTracking.h>
|
|
#include <AzCore/std/string/conversions.h>
|
|
#include <AzFramework/StringFunc/StringFunc.h>
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#undef AZ_RESTRICTED_SECTION
|
|
#define TEXTURE_CPP_SECTION_1 1
|
|
#define TEXTURE_CPP_SECTION_2 2
|
|
#define TEXTURE_CPP_SECTION_3 3
|
|
#define TEXTURE_CPP_SECTION_4 4
|
|
#define TEXTURE_CPP_SECTION_5 5
|
|
#define TEXTURE_CPP_SECTION_6 6
|
|
#define TEXTURE_CPP_SECTION_7 7
|
|
#endif
|
|
|
|
#if defined(OPENGL_ES) || defined(CRY_USE_METAL)
|
|
#include "../../XRenderD3D9/DriverD3D.h" // for gcpRendD3D
|
|
#endif
|
|
|
|
#define TEXTURE_LEVEL_CACHE_PAK "dds0.pak"
|
|
|
|
STexState CTexture::s_sDefState;
|
|
STexStageInfo CTexture::s_TexStages[MAX_TMU];
|
|
int CTexture::s_nStreamingMode;
|
|
int CTexture::s_nStreamingUpdateMode;
|
|
bool CTexture::s_bPrecachePhase;
|
|
bool CTexture::s_bInLevelPhase = false;
|
|
bool CTexture::s_bPrestreamPhase;
|
|
int CTexture::s_nStreamingThroughput = 0;
|
|
float CTexture::s_nStreamingTotalTime = 0;
|
|
AZStd::vector<STexState, AZ::StdLegacyAllocator> CTexture::s_TexStates;
|
|
CTextureStreamPoolMgr* CTexture::s_pPoolMgr;
|
|
AZStd::set<string, AZStd::less<string>, AZ::StdLegacyAllocator> CTexture::s_vTexReloadRequests;
|
|
CryCriticalSection CTexture::s_xTexReloadLock;
|
|
#ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
|
|
StaticInstance<CTexture::LowResSystemCopyType> CTexture::s_LowResSystemCopy;
|
|
#endif
|
|
|
|
StaticInstance<AZStd::mutex> CTexture::m_staticInvalidateCallbacksMutex;
|
|
|
|
bool CTexture::m_bLoadedSystem;
|
|
|
|
CTexture* CTexture::s_ptexMipColors_Diffuse;
|
|
CTexture* CTexture::s_ptexMipColors_Bump;
|
|
CTexture* CTexture::s_ptexFromRE[8];
|
|
CTexture* CTexture::s_ptexShadowID[8];
|
|
CTexture* CTexture::s_ptexShadowMask;
|
|
CTexture* CTexture::s_ptexCachedShadowMap[MAX_GSM_LODS_NUM];
|
|
CTexture* CTexture::s_ptexNearestShadowMap;
|
|
CTexture* CTexture::s_ptexHeightMapAO[2];
|
|
CTexture* CTexture::s_ptexHeightMapAODepth[2];
|
|
CTexture* CTexture::s_ptexFromRE_FromContainer[2];
|
|
CTexture* CTexture::s_ptexFromObj;
|
|
CTexture* CTexture::s_ptexSvoTree;
|
|
CTexture* CTexture::s_ptexSvoTris;
|
|
CTexture* CTexture::s_ptexSvoGlobalCM;
|
|
CTexture* CTexture::s_ptexSvoRgbs;
|
|
CTexture* CTexture::s_ptexSvoNorm;
|
|
CTexture* CTexture::s_ptexSvoOpac;
|
|
CTexture* CTexture::s_ptexFromObjCM;
|
|
CTexture* CTexture::s_ptexRT_2D;
|
|
CTexture* CTexture::s_ptexSceneNormalsMap;
|
|
CTexture* CTexture::s_ptexSceneNormalsMapMS;
|
|
CTexture* CTexture::s_ptexSceneNormalsBent;
|
|
CTexture* CTexture::s_ptexAOColorBleed;
|
|
CTexture* CTexture::s_ptexSceneDiffuse;
|
|
CTexture* CTexture::s_ptexSceneSpecular;
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION TEXTURE_CPP_SECTION_1
|
|
#include AZ_RESTRICTED_FILE(Texture_cpp)
|
|
#endif
|
|
CTexture* CTexture::s_ptexAmbientLookup;
|
|
|
|
// Post-process related textures
|
|
CTexture* CTexture::s_ptexBackBuffer;
|
|
CTexture* CTexture::s_ptexModelHudBuffer;
|
|
CTexture* CTexture::s_ptexPrevBackBuffer[2][2] = {
|
|
{NULL}
|
|
};
|
|
CTexture* CTexture::s_ptexCached3DHud;
|
|
CTexture* CTexture::s_ptexCached3DHudScaled;
|
|
CTexture* CTexture::s_ptexBackBufferScaled[3];
|
|
CTexture* CTexture::s_ptexBackBufferScaledTemp[2];
|
|
CTexture* CTexture::s_ptexPrevFrameScaled;
|
|
|
|
CTexture* CTexture::s_ptexDepthBufferQuarter;
|
|
|
|
CTexture* CTexture::s_ptexWaterOcean;
|
|
CTexture* CTexture::s_ptexWaterVolumeTemp;
|
|
CTexture* CTexture::s_ptexWaterVolumeDDN;
|
|
CTexture* CTexture::s_ptexWaterVolumeRefl[2];
|
|
CTexture* CTexture::s_ptexWaterCaustics[2];
|
|
CTexture* CTexture::s_ptexWaterRipplesDDN;
|
|
CTexture* CTexture::s_ptexRainOcclusion;
|
|
CTexture* CTexture::s_ptexRainSSOcclusion[2];
|
|
|
|
CTexture* CTexture::s_ptexRainDropsRT[2];
|
|
|
|
CTexture* CTexture::s_ptexRT_ShadowPool;
|
|
CTexture* CTexture::s_ptexRT_ShadowStub;
|
|
CTexture* CTexture::s_ptexCloudsLM;
|
|
|
|
CTexture* CTexture::s_ptexSceneTarget = NULL;
|
|
CTexture* CTexture::s_ptexSceneTargetR11G11B10F[2] = {NULL};
|
|
CTexture* CTexture::s_ptexSceneTargetScaledR11G11B10F[4] = {NULL};
|
|
CTexture* CTexture::s_ptexCurrSceneTarget;
|
|
CTexture* CTexture::s_ptexCurrentSceneDiffuseAccMap;
|
|
CTexture* CTexture::s_ptexSceneDiffuseAccMap;
|
|
CTexture* CTexture::s_ptexSceneSpecularAccMap;
|
|
CTexture* CTexture::s_ptexSceneDiffuseAccMapMS;
|
|
CTexture* CTexture::s_ptexSceneSpecularAccMapMS;
|
|
CTexture* CTexture::s_ptexZTarget;
|
|
CTexture* CTexture::s_ptexZTargetDownSample[4];
|
|
CTexture* CTexture::s_ptexZTargetScaled;
|
|
CTexture* CTexture::s_ptexZTargetScaled2;
|
|
CTexture* CTexture::s_ptexHDRTarget;
|
|
CTexture* CTexture::s_ptexVelocity;
|
|
CTexture* CTexture::s_ptexVelocityTiles[3] = {NULL};
|
|
CTexture* CTexture::s_ptexVelocityObjects[2] = {NULL};
|
|
|
|
CTexture* CTexture::s_ptexFurZTarget;
|
|
CTexture* CTexture::s_ptexFurLightAcc;
|
|
CTexture* CTexture::s_ptexFurPrepass;
|
|
|
|
// Confetti Begin: David Srour
|
|
CTexture* CTexture::s_ptexGmemStenLinDepth = NULL;
|
|
// Confetti End
|
|
CTexture* CTexture::s_ptexHDRTargetPrev = NULL;
|
|
CTexture* CTexture::s_ptexHDRTargetScaled[4];
|
|
CTexture* CTexture::s_ptexHDRTargetScaledTmp[4];
|
|
CTexture* CTexture::s_ptexHDRTargetScaledTempRT[4];
|
|
CTexture* CTexture::s_ptexHDRDofLayers[2];
|
|
|
|
CTexture* CTexture::s_ptexSceneCoCHistory[2] = {};
|
|
CTexture* CTexture::s_ptexSceneCoC[MIN_DOF_COC_K] = {};
|
|
CTexture* CTexture::s_ptexSceneCoCTemp = NULL;
|
|
CTexture* CTexture::s_ptexHDRTempBloom[2];
|
|
CTexture* CTexture::s_ptexHDRFinalBloom;
|
|
CTexture* CTexture::s_ptexHDRAdaptedLuminanceCur[8];
|
|
int CTexture::s_nCurLumTextureIndex;
|
|
CTexture* CTexture::s_ptexCurLumTexture;
|
|
CTexture* CTexture::s_ptexHDRToneMaps[NUM_HDR_TONEMAP_TEXTURES];
|
|
CTexture* CTexture::s_ptexHDRMeasuredLuminance[MAX_GPU_NUM];
|
|
CTexture* CTexture::s_ptexHDRMeasuredLuminanceDummy;
|
|
CTexture* CTexture::s_ptexSkyDomeMie;
|
|
CTexture* CTexture::s_ptexSkyDomeRayleigh;
|
|
CTexture* CTexture::s_ptexSkyDomeMoon;
|
|
CTexture* CTexture::s_ptexVolObj_Density;
|
|
CTexture* CTexture::s_ptexVolObj_Shadow;
|
|
CTexture* CTexture::s_ptexColorChart;
|
|
CTexture* CTexture::s_ptexSceneTargetScaled;
|
|
CTexture* CTexture::s_ptexSceneTargetScaledBlurred;
|
|
CTexture* CTexture::s_ptexStereoL = NULL;
|
|
CTexture* CTexture::s_ptexStereoR = NULL;
|
|
|
|
CTexture* CTexture::s_ptexFlaresOcclusionRing[MAX_OCCLUSION_READBACK_TEXTURES] = {NULL};
|
|
CTexture* CTexture::s_ptexFlaresGather = NULL;
|
|
|
|
SEnvTexture CTexture::s_EnvCMaps[MAX_ENVCUBEMAPS];
|
|
SEnvTexture CTexture::s_EnvTexts[MAX_ENVTEXTURES];
|
|
|
|
StaticInstance<TArray<SEnvTexture>> CTexture::s_CustomRT_2D;
|
|
|
|
StaticInstance<TArray<CTexture>> CTexture::s_ShaderTemplates(EFTT_MAX);
|
|
bool CTexture::s_ShaderTemplatesInitialized = false;
|
|
|
|
CTexture* CTexture::s_pTexNULL = 0;
|
|
|
|
CTexture* CTexture::s_pBackBuffer;
|
|
CTexture* CTexture::s_FrontBufferTextures[2] = { NULL };
|
|
|
|
CTexture* CTexture::s_ptexVolumetricFog = NULL;
|
|
CTexture* CTexture::s_ptexVolumetricFogDensityColor = NULL;
|
|
CTexture* CTexture::s_ptexVolumetricFogDensity = NULL;
|
|
CTexture* CTexture::s_ptexVolumetricClipVolumeStencil = NULL;
|
|
|
|
#if defined(TEXSTRM_DEFERRED_UPLOAD)
|
|
ID3D11DeviceContext* CTexture::s_pStreamDeferredCtx;
|
|
#endif
|
|
|
|
#if defined(VOLUMETRIC_FOG_SHADOWS)
|
|
CTexture* CTexture::s_ptexVolFogShadowBuf[2] = {0};
|
|
#endif
|
|
|
|
CTexture* CTexture::s_defaultEnvironmentProbeDummy = nullptr;
|
|
|
|
ETEX_Format CTexture::s_eTFZ = eTF_R32F;
|
|
|
|
//============================================================
|
|
|
|
SResourceView SResourceView::ShaderResourceView(ETEX_Format nFormat, int nFirstSlice, int nSliceCount, int nMostDetailedMip, int nMipCount, bool bSrgbRead, bool bMultisample)
|
|
{
|
|
SResourceView result(0);
|
|
|
|
result.m_Desc.eViewType = eShaderResourceView;
|
|
result.m_Desc.nFormat = nFormat;
|
|
result.m_Desc.nFirstSlice = nFirstSlice;
|
|
result.m_Desc.nSliceCount = nSliceCount;
|
|
result.m_Desc.nMostDetailedMip = nMostDetailedMip;
|
|
result.m_Desc.nMipCount = nMipCount;
|
|
result.m_Desc.bSrgbRead = bSrgbRead ? 1 : 0;
|
|
result.m_Desc.bMultisample = bMultisample ? 1 : 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
SResourceView SResourceView::RenderTargetView(ETEX_Format nFormat, int nFirstSlice, int nSliceCount, int nMipLevel, bool bMultisample)
|
|
{
|
|
SResourceView result(0);
|
|
|
|
result.m_Desc.eViewType = eRenderTargetView;
|
|
result.m_Desc.nFormat = nFormat;
|
|
result.m_Desc.nFirstSlice = nFirstSlice;
|
|
result.m_Desc.nSliceCount = nSliceCount;
|
|
result.m_Desc.nMostDetailedMip = nMipLevel;
|
|
result.m_Desc.bMultisample = bMultisample ? 1 : 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
SResourceView SResourceView::DepthStencilView(ETEX_Format nFormat, int nFirstSlice, int nSliceCount, int nMipLevel, int nFlags, bool bMultisample)
|
|
{
|
|
SResourceView result(0);
|
|
|
|
result.m_Desc.eViewType = eDepthStencilView;
|
|
result.m_Desc.nFormat = nFormat;
|
|
result.m_Desc.nFirstSlice = nFirstSlice;
|
|
result.m_Desc.nSliceCount = nSliceCount;
|
|
result.m_Desc.nMostDetailedMip = nMipLevel;
|
|
result.m_Desc.nFlags = nFlags;
|
|
result.m_Desc.bMultisample = bMultisample ? 1 : 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
SResourceView SResourceView::UnorderedAccessView(ETEX_Format nFormat, int nFirstSlice, int nSliceCount, int nMipLevel, int nFlags)
|
|
{
|
|
SResourceView result(0);
|
|
|
|
result.m_Desc.eViewType = eUnorderedAccessView;
|
|
result.m_Desc.nFormat = nFormat;
|
|
result.m_Desc.nFirstSlice = nFirstSlice;
|
|
result.m_Desc.nSliceCount = nSliceCount;
|
|
result.m_Desc.nMostDetailedMip = nMipLevel;
|
|
result.m_Desc.nFlags = (nFlags & FT_USAGE_UAV_RWTEXTURE) ? 1 : 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
//============================================================
|
|
|
|
CTexture::~CTexture()
|
|
{
|
|
// sizes of these structures should NOT exceed L2 cache line!
|
|
// offsetof with MSVC's crt and clang produces an error
|
|
#if defined(PLATFORM_64BIT) && !(defined(AZ_PLATFORM_WINDOWS) && defined(AZ_COMPILER_CLANG))
|
|
COMPILE_TIME_ASSERT((offsetof(CTexture, m_composition) - offsetof(CTexture, m_pFileTexMips)) <= 64);
|
|
COMPILE_TIME_ASSERT((offsetof(CTexture, m_pFileTexMips) % 64) == 0);
|
|
#endif
|
|
|
|
#ifndef _RELEASE
|
|
if (!gRenDev->m_pRT->IsRenderThread() || gRenDev->m_pRT->IsRenderLoadingThread())
|
|
{
|
|
__debugbreak();
|
|
}
|
|
#endif
|
|
|
|
#ifndef _RELEASE
|
|
if (IsStreaming())
|
|
{
|
|
__debugbreak();
|
|
}
|
|
#endif
|
|
|
|
if (gRenDev && gRenDev->m_pRT)
|
|
{
|
|
gRenDev->m_pRT->RC_ReleaseDeviceTexture(this);
|
|
}
|
|
|
|
if (m_pFileTexMips)
|
|
{
|
|
Unlink();
|
|
StreamState_ReleaseInfo(this, m_pFileTexMips);
|
|
m_pFileTexMips = NULL;
|
|
}
|
|
|
|
#ifdef ENABLE_TEXTURE_STREAM_LISTENER
|
|
if (s_pStreamListener)
|
|
{
|
|
s_pStreamListener->OnDestroyedStreamedTexture(this);
|
|
}
|
|
#endif
|
|
|
|
#ifndef _RELEASE
|
|
if (m_bInDistanceSortedList)
|
|
{
|
|
__debugbreak();
|
|
}
|
|
#endif
|
|
|
|
#ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
|
|
s_LowResSystemCopy.erase(this);
|
|
#endif
|
|
|
|
#if defined(USE_UNIQUE_MUTEX_PER_TEXTURE)
|
|
if (gEnv->IsEditor())
|
|
{
|
|
// Only the editor allocated a unique mutex per texture.
|
|
delete m_invalidateCallbacksMutex;
|
|
m_invalidateCallbacksMutex = nullptr;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CTexture::RT_ReleaseDevice()
|
|
{
|
|
ReleaseDeviceTexture(false);
|
|
}
|
|
|
|
const CCryNameTSCRC& CTexture::mfGetClassName()
|
|
{
|
|
return s_sClassName;
|
|
}
|
|
|
|
CCryNameTSCRC CTexture::GenName(const char* name, uint32 nFlags)
|
|
{
|
|
char buffer[AZ_MAX_PATH_LEN];
|
|
IResourceCompilerHelper::GetOutputFilename(name, buffer, sizeof(buffer)); // change texture filename extensions to dds before we compute the crc
|
|
stack_string strName = buffer;
|
|
strName.MakeLower();
|
|
|
|
//'\\' in texture names causing duplication
|
|
PathUtil::ToUnixPath(strName);
|
|
|
|
if (nFlags & FT_ALPHA)
|
|
{
|
|
strName += "_a";
|
|
}
|
|
|
|
return CCryNameTSCRC(strName.c_str());
|
|
}
|
|
|
|
class StrComp
|
|
{
|
|
public:
|
|
bool operator () (const char* s1, const char* s2) const {return strcmp(s1, s2) < 0; }
|
|
};
|
|
|
|
|
|
CTexture* CTexture::GetByID(int nID)
|
|
{
|
|
CTexture* pTex = NULL;
|
|
|
|
const CCryNameTSCRC& className = mfGetClassName();
|
|
CBaseResource* pBR = CBaseResource::GetResource(className, nID, false);
|
|
if (!pBR)
|
|
{
|
|
return CTextureManager::Instance()->GetNoTexture();
|
|
}
|
|
pTex = (CTexture*)pBR;
|
|
return pTex;
|
|
}
|
|
|
|
CTexture* CTexture::GetByName(const char* szName, uint32 flags)
|
|
{
|
|
CTexture* pTex = NULL;
|
|
|
|
CCryNameTSCRC Name = GenName(szName, flags);
|
|
|
|
CBaseResource* pBR = CBaseResource::GetResource(mfGetClassName(), Name, false);
|
|
if (!pBR)
|
|
{
|
|
return NULL;
|
|
}
|
|
pTex = (CTexture*)pBR;
|
|
return pTex;
|
|
}
|
|
|
|
CTexture* CTexture::GetByNameCRC(CCryNameTSCRC Name)
|
|
{
|
|
CTexture* pTex = NULL;
|
|
|
|
CBaseResource* pBR = CBaseResource::GetResource(mfGetClassName(), Name, false);
|
|
if (!pBR)
|
|
{
|
|
return NULL;
|
|
}
|
|
pTex = (CTexture*)pBR;
|
|
return pTex;
|
|
}
|
|
|
|
CTexture* CTexture::NewTexture(const char* name, uint32 nFlags, ETEX_Format eTFDst, bool& bFound)
|
|
{
|
|
AZ_ASSET_NAMED_SCOPE("CTexture::NewTexture: %s", name);
|
|
|
|
CTexture* pTex = NULL;
|
|
AZStd::string normalizedFile;
|
|
AZStd::string fileExtension;
|
|
AzFramework::StringFunc::Path::GetExtension(name, fileExtension);
|
|
if (name[0] == '$' || fileExtension.empty())
|
|
{
|
|
//If the name starts with $ or it does not have any extension then it is one of the special texture
|
|
// that the engine requires and we would not be modifying the name
|
|
normalizedFile = name;
|
|
}
|
|
else
|
|
{
|
|
char buffer[AZ_MAX_PATH_LEN];
|
|
IResourceCompilerHelper::GetOutputFilename(name, buffer, sizeof(buffer)); // change texture filename extensions to dds
|
|
normalizedFile = buffer;
|
|
AZStd::to_lower(normalizedFile.begin(), normalizedFile.end());
|
|
PathUtil::ToUnixPath(normalizedFile.c_str());
|
|
}
|
|
|
|
CCryNameTSCRC Name = GenName(normalizedFile.c_str(), nFlags);
|
|
|
|
CBaseResource* pBR = CBaseResource::GetResource(mfGetClassName(), Name, false);
|
|
if (!pBR)
|
|
{
|
|
//If a texture name ends in _stereo we want to create a stereo texture
|
|
const AZStd::string ending = "_stereo";
|
|
AZStd::string fullName = normalizedFile.c_str();
|
|
size_t nameLength = fullName.length();
|
|
size_t endingLength = ending.length();
|
|
if (nameLength > endingLength && fullName.compare(nameLength - endingLength, endingLength, ending) == 0)
|
|
{
|
|
pTex = new CStereoTexture(normalizedFile.c_str(), eTFDst, nFlags);
|
|
}
|
|
else
|
|
{
|
|
pTex = new CTexture(nFlags);
|
|
}
|
|
pTex->Register(mfGetClassName(), Name);
|
|
bFound = false;
|
|
pTex->m_nFlags = nFlags;
|
|
pTex->m_eTFDst = eTFDst;
|
|
pTex->m_SrcName = normalizedFile.c_str();
|
|
}
|
|
else
|
|
{
|
|
pTex = (CTexture*)pBR;
|
|
pTex->AddRef();
|
|
bFound = true;
|
|
}
|
|
|
|
return pTex;
|
|
}
|
|
|
|
void CTexture::SetDevTexture([[maybe_unused]] CDeviceTexture* pDeviceTex)
|
|
{
|
|
#if !defined(NULL_RENDERER)
|
|
SAFE_RELEASE(m_pDevTexture);
|
|
m_pDevTexture = pDeviceTex;
|
|
if (m_pDevTexture)
|
|
{
|
|
m_pDevTexture->SetNoDelete(!!(m_nFlags & FT_DONT_RELEASE));
|
|
}
|
|
InvalidateDeviceResource(eDeviceResourceDirty);
|
|
#endif
|
|
}
|
|
|
|
void CTexture::PostCreate()
|
|
{
|
|
m_nUpdateFrameID = gRenDev->GetFrameID(false);
|
|
m_bPostponed = false;
|
|
}
|
|
|
|
CTexture* CTexture::CreateTextureObject(const char* name, uint32 nWidth, uint32 nHeight, int nDepth, ETEX_Type eTT, uint32 nFlags, ETEX_Format eTF, int nCustomID)
|
|
{
|
|
SYNCHRONOUS_LOADING_TICK();
|
|
|
|
bool bFound = false;
|
|
|
|
CTexture* pTex = NewTexture(name, nFlags, eTF, bFound);
|
|
if (bFound)
|
|
{
|
|
if (!pTex->m_nWidth)
|
|
{
|
|
pTex->m_nWidth = nWidth;
|
|
}
|
|
if (!pTex->m_nHeight)
|
|
{
|
|
pTex->m_nHeight = nHeight;
|
|
}
|
|
pTex->m_nFlags |= nFlags & (FT_DONT_RELEASE | FT_USAGE_RENDERTARGET);
|
|
|
|
return pTex;
|
|
}
|
|
pTex->m_nDepth = nDepth;
|
|
pTex->m_nWidth = nWidth;
|
|
pTex->m_nHeight = nHeight;
|
|
pTex->m_eTT = eTT;
|
|
pTex->m_eTFDst = eTF;
|
|
pTex->m_nCustomID = nCustomID;
|
|
pTex->m_SrcName = name;
|
|
|
|
return pTex;
|
|
}
|
|
|
|
void CTexture::GetMemoryUsage(ICrySizer* pSizer) const
|
|
{
|
|
pSizer->Add(*this);
|
|
pSizer->AddObject(m_SrcName);
|
|
|
|
#ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
|
|
const LowResSystemCopyType::iterator& it = s_LowResSystemCopy.find(this);
|
|
if (it != CTexture::s_LowResSystemCopy.end())
|
|
{
|
|
pSizer->AddObject((*it).second.m_lowResSystemCopy);
|
|
}
|
|
#endif
|
|
|
|
if (m_pFileTexMips)
|
|
{
|
|
m_pFileTexMips->GetMemoryUsage(pSizer, m_nMips, m_CacheFileHeader.m_nSides);
|
|
}
|
|
}
|
|
|
|
|
|
CTexture* CTexture::CreateTextureArray(const char* name, ETEX_Type eType, uint32 nWidth, uint32 nHeight, uint32 nArraySize, int nMips, uint32 nFlags, ETEX_Format eTF, int nCustomID)
|
|
{
|
|
assert(eType == eTT_2D || eType == eTT_Cube);
|
|
|
|
if (nArraySize > 255)
|
|
{
|
|
assert(0);
|
|
return NULL;
|
|
}
|
|
|
|
if (nMips <= 0)
|
|
{
|
|
nMips = CTexture::CalcNumMips(nWidth, nHeight);
|
|
}
|
|
|
|
bool sRGB = (nFlags & FT_USAGE_ALLOWREADSRGB) != 0;
|
|
nFlags &= ~FT_USAGE_ALLOWREADSRGB;
|
|
|
|
CTexture* pTex = CreateTextureObject(name, nWidth, nHeight, 1, eType, nFlags, eTF, nCustomID);
|
|
pTex->m_nWidth = nWidth;
|
|
pTex->m_nHeight = nHeight;
|
|
pTex->m_nArraySize = nArraySize;
|
|
pTex->m_nFlags |= eType == eTT_Cube ? FT_REPLICATE_TO_ALL_SIDES : 0;
|
|
|
|
if (nFlags & FT_USAGE_RENDERTARGET)
|
|
{
|
|
bool bRes = pTex->CreateRenderTarget(eTF, Clr_Unknown);
|
|
if (!bRes)
|
|
{
|
|
pTex->m_nFlags |= FT_FAILED;
|
|
}
|
|
pTex->PostCreate();
|
|
}
|
|
else
|
|
{
|
|
STexData td;
|
|
td.m_eTF = eTF;
|
|
td.m_nDepth = 1;
|
|
td.m_nWidth = nWidth;
|
|
td.m_nHeight = nHeight;
|
|
td.m_nMips = nMips;
|
|
td.m_nFlags = sRGB ? FIM_SRGB_READ : 0;
|
|
|
|
bool bRes = pTex->CreateTexture(td);
|
|
if (!bRes)
|
|
{
|
|
pTex->m_nFlags |= FT_FAILED;
|
|
}
|
|
pTex->PostCreate();
|
|
}
|
|
|
|
pTex->m_nFlags &= ~FT_REPLICATE_TO_ALL_SIDES;
|
|
|
|
return pTex;
|
|
}
|
|
|
|
CTexture* CTexture::CreateRenderTarget(const char* name, uint32 nWidth, uint32 nHeight, const ColorF& cClear, ETEX_Type eTT, uint32 nFlags, ETEX_Format eTF, int nCustomID)
|
|
{
|
|
AZ_ASSET_NAMED_SCOPE("CTexture::CreateRenderTarget: %s", name);
|
|
|
|
CTexture* pTex = CreateTextureObject(name, nWidth, nHeight, 1, eTT, nFlags | FT_USAGE_RENDERTARGET, eTF, nCustomID);
|
|
pTex->m_nWidth = nWidth;
|
|
pTex->m_nHeight = nHeight;
|
|
pTex->m_nFlags |= nFlags;
|
|
|
|
bool bRes = pTex->CreateRenderTarget(eTF, cClear);
|
|
if (!bRes)
|
|
{
|
|
pTex->m_nFlags |= FT_FAILED;
|
|
}
|
|
pTex->PostCreate();
|
|
|
|
return pTex;
|
|
}
|
|
|
|
// 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 CTexture::Create2DTextureWithMips(int nWidth, int nHeight, int nMips, [[maybe_unused]] int nFlags, const byte* pData, ETEX_Format eTFSrc, [[maybe_unused]] ETEX_Format eTFDst)
|
|
{
|
|
if (nMips <= 0)
|
|
{
|
|
nMips = CTexture::CalcNumMips(nWidth, nHeight);
|
|
}
|
|
m_eTFSrc = eTFSrc;
|
|
m_nMips = nMips;
|
|
|
|
STexData td;
|
|
td.m_eTF = eTFSrc;
|
|
td.m_nDepth = 1;
|
|
td.m_nWidth = nWidth;
|
|
td.m_nHeight = nHeight;
|
|
// Propagate mips correctly. (Create2DTexture always sets this to 1)
|
|
td.m_nMips = nMips;
|
|
td.m_pData[0] = pData;
|
|
|
|
bool bRes = CreateTexture(td);
|
|
if (!bRes)
|
|
{
|
|
m_nFlags |= FT_FAILED;
|
|
}
|
|
|
|
PostCreate();
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CTexture::Create2DTexture(int nWidth, int nHeight, int nMips, [[maybe_unused]] int nFlags, const byte* pData, ETEX_Format eTFSrc, [[maybe_unused]] ETEX_Format eTFDst)
|
|
{
|
|
if (nMips <= 0)
|
|
{
|
|
nMips = CTexture::CalcNumMips(nWidth, nHeight);
|
|
}
|
|
m_eTFSrc = eTFSrc;
|
|
m_nMips = nMips;
|
|
|
|
STexData td;
|
|
td.m_eTF = eTFSrc;
|
|
td.m_nDepth = 1;
|
|
td.m_nWidth = nWidth;
|
|
td.m_nHeight = nHeight;
|
|
td.m_nMips = 1;
|
|
td.m_pData[0] = pData;
|
|
|
|
bool bRes = CreateTexture(td);
|
|
if (!bRes)
|
|
{
|
|
m_nFlags |= FT_FAILED;
|
|
}
|
|
|
|
PostCreate();
|
|
|
|
return bRes;
|
|
}
|
|
|
|
CTexture* CTexture::Create2DTexture(const char* szName, int nWidth, int nHeight, int nMips, int nFlags, const byte* pData, ETEX_Format eTFSrc, ETEX_Format eTFDst, bool bAsyncDevTexCreation)
|
|
{
|
|
FUNCTION_PROFILER_FAST(GetISystem(), PROFILE_RENDERER, g_bProfilerEnabled);
|
|
|
|
CTexture* pTex = CreateTextureObject(szName, nWidth, nHeight, 1, eTT_2D, nFlags, eTFDst, -1);
|
|
pTex->m_bAsyncDevTexCreation = bAsyncDevTexCreation;
|
|
bool bFound = false;
|
|
|
|
pTex->Create2DTexture(nWidth, nHeight, nMips, nFlags, pData, eTFSrc, eTFDst);
|
|
|
|
return pTex;
|
|
}
|
|
|
|
bool CTexture::Create3DTexture(int nWidth, int nHeight, int nDepth, int nMips, [[maybe_unused]] int nFlags, const byte* pData, ETEX_Format eTFSrc, [[maybe_unused]] ETEX_Format eTFDst)
|
|
{
|
|
m_eTFSrc = eTFSrc;
|
|
m_nMips = nMips;
|
|
|
|
STexData td;
|
|
td.m_eTF = eTFSrc;
|
|
td.m_nWidth = nWidth;
|
|
td.m_nHeight = nHeight;
|
|
td.m_nDepth = nDepth;
|
|
td.m_nMips = nMips;
|
|
td.m_pData[0] = pData;
|
|
|
|
bool bRes = CreateTexture(td);
|
|
if (!bRes)
|
|
{
|
|
m_nFlags |= FT_FAILED;
|
|
}
|
|
|
|
PostCreate();
|
|
|
|
return bRes;
|
|
}
|
|
|
|
CTexture* CTexture::Create3DTexture(const char* szName, int nWidth, int nHeight, int nDepth, int nMips, int nFlags, const byte* pData, ETEX_Format eTFSrc, ETEX_Format eTFDst)
|
|
{
|
|
CTexture* pTex = CreateTextureObject(szName, nWidth, nHeight, nDepth, eTT_3D, nFlags, eTFDst, -1);
|
|
bool bFound = false;
|
|
|
|
pTex->Create3DTexture(nWidth, nHeight, nDepth, nMips, nFlags, pData, eTFSrc, eTFDst);
|
|
|
|
return pTex;
|
|
}
|
|
|
|
CTexture* CTexture::Create2DCompositeTexture(const char* szName, int nWidth, int nHeight, int nMips, int nFlags, ETEX_Format eTFDst, const STexComposition* pCompositions, size_t nCompositions)
|
|
{
|
|
nFlags |= FT_COMPOSITE;
|
|
nFlags &= ~FT_DONT_STREAM;
|
|
|
|
bool bFound = false;
|
|
CTexture* pTex = NewTexture(szName, nFlags, eTFDst, bFound);
|
|
|
|
if (!bFound)
|
|
{
|
|
pTex->m_nWidth = nWidth;
|
|
pTex->m_nHeight = nHeight;
|
|
pTex->m_nMips = nMips;
|
|
pTex->m_composition.assign(pCompositions, pCompositions + nCompositions);
|
|
|
|
// Strip all invalid textures from the composition
|
|
|
|
int w = 0;
|
|
for (int r = 0, c = pTex->m_composition.size(); r != c; ++r)
|
|
{
|
|
if (!pTex->m_composition[r].pTexture)
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, "Composition %i for '%s' is missing", r, szName);
|
|
continue;
|
|
}
|
|
|
|
if (r != w)
|
|
{
|
|
pTex->m_composition[w] = pTex->m_composition[r];
|
|
}
|
|
++w;
|
|
}
|
|
pTex->m_composition.resize(w);
|
|
|
|
if (CTexture::s_bPrecachePhase)
|
|
{
|
|
pTex->m_bPostponed = true;
|
|
pTex->m_bWasUnloaded = true;
|
|
}
|
|
else
|
|
{
|
|
pTex->StreamPrepareComposition();
|
|
}
|
|
}
|
|
|
|
return pTex;
|
|
}
|
|
|
|
bool CTexture::Reload()
|
|
{
|
|
const byte* pData[6];
|
|
int i;
|
|
bool bOK = false;
|
|
|
|
if (IsStreamed())
|
|
{
|
|
ReleaseDeviceTexture(false);
|
|
return ToggleStreaming(true);
|
|
}
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
pData[i] = 0;
|
|
}
|
|
if (m_nFlags & FT_FROMIMAGE)
|
|
{
|
|
assert(!(m_nFlags & FT_USAGE_RENDERTARGET));
|
|
bOK = LoadFromImage(m_SrcName.c_str()); // true=reloading
|
|
if (!bOK)
|
|
{
|
|
SetNoTexture(m_eTT == eTT_Cube ? CTextureManager::Instance()->GetNoTextureCM() : CTextureManager::Instance()->GetNoTexture() );
|
|
}
|
|
}
|
|
else
|
|
if (m_nFlags & (FT_USAGE_RENDERTARGET | FT_USAGE_DYNAMIC))
|
|
{
|
|
bOK = CreateDeviceTexture(pData);
|
|
assert(bOK);
|
|
}
|
|
|
|
// Post Create assumes the texture loaded successfully so don't call it if that's not the case
|
|
if (bOK)
|
|
{
|
|
PostCreate();
|
|
}
|
|
|
|
return bOK;
|
|
}
|
|
|
|
CTexture* CTexture::ForName(const char* name, uint32 nFlags, ETEX_Format eTFDst)
|
|
{
|
|
SLICE_AND_SLEEP();
|
|
AZ_ASSET_NAMED_SCOPE("CTexture::ForName: %s", name);
|
|
|
|
bool bFound = false;
|
|
|
|
CRY_DEFINE_ASSET_SCOPE("Texture", name);
|
|
|
|
CTexture* pTex = NewTexture(name, nFlags, eTFDst, bFound);
|
|
if (bFound || name[0] == '$')
|
|
{
|
|
if (!bFound)
|
|
{
|
|
pTex->m_SrcName = name;
|
|
}
|
|
else
|
|
{
|
|
// switch off streaming for the same texture with the same flags except DONT_STREAM
|
|
if ((nFlags & FT_DONT_STREAM) != 0 && (pTex->GetFlags() & FT_DONT_STREAM) == 0)
|
|
{
|
|
if (!pTex->m_bPostponed)
|
|
{
|
|
pTex->ReleaseDeviceTexture(false);
|
|
}
|
|
pTex->m_nFlags |= FT_DONT_STREAM;
|
|
if (!pTex->m_bPostponed)
|
|
{
|
|
pTex->Reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
return pTex;
|
|
}
|
|
pTex->m_SrcName = name;
|
|
|
|
#ifndef _RELEASE
|
|
pTex->m_sAssetScopeName = gEnv->pLog->GetAssetScopeString();
|
|
#endif
|
|
bool bPrecachePhase = CTexture::s_bPrecachePhase && !(nFlags & FT_IGNORE_PRECACHE);
|
|
|
|
ESystemGlobalState currentGlobalState = GetISystem()->GetSystemGlobalState();
|
|
const bool levelLoading = currentGlobalState == ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START;
|
|
|
|
// Load textures immediately during level load since texture load
|
|
// requests during this phase are probably coming from a loading screen.
|
|
if (levelLoading || !bPrecachePhase)
|
|
{
|
|
pTex->Load(eTFDst);
|
|
}
|
|
else
|
|
{
|
|
// NOTE: attached alpha isn't detectable by flags before the header is loaded, so we do it by file-suffix
|
|
if (/*(nFlags & FT_TEX_NORMAL_MAP) &&*/ TextureHelpers::VerifyTexSuffix(EFTT_NORMALS, name) && TextureHelpers::VerifyTexSuffix(EFTT_SMOOTHNESS, name))
|
|
{
|
|
nFlags |= FT_HAS_ATTACHED_ALPHA;
|
|
}
|
|
|
|
pTex->m_eTFDst = eTFDst;
|
|
pTex->m_nFlags = nFlags;
|
|
pTex->m_bPostponed = true;
|
|
pTex->m_bWasUnloaded = true;
|
|
}
|
|
|
|
return pTex;
|
|
}
|
|
|
|
struct CompareTextures
|
|
{
|
|
bool operator()(const CTexture* a, const CTexture* b)
|
|
{
|
|
return (azstricmp(a->GetSourceName(), b->GetSourceName()) < 0);
|
|
}
|
|
};
|
|
|
|
void CTexture::Precache()
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION(iSystem);
|
|
|
|
if (!s_bPrecachePhase)
|
|
{
|
|
return;
|
|
}
|
|
if (!gRenDev)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CryLog("Requesting textures precache ...");
|
|
|
|
gRenDev->m_pRT->RC_PreloadTextures();
|
|
}
|
|
|
|
void CTexture::RT_Precache()
|
|
{
|
|
if (gRenDev->CheckDeviceLost())
|
|
{
|
|
return;
|
|
}
|
|
|
|
LOADING_TIME_PROFILE_SECTION(iSystem);
|
|
AZ_TRACE_METHOD();
|
|
|
|
// Disable invalid file access logging if texture streaming is disabled
|
|
// If texture streaming is turned off, we will hit this on the renderthread
|
|
// and stall due to the invalid file access stalls
|
|
ICVar* sysPakLogInvalidAccess = NULL;
|
|
int pakLogFileAccess = 0;
|
|
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_texturesstreaming)
|
|
{
|
|
if (sysPakLogInvalidAccess = gEnv->pConsole->GetCVar("sys_PakLogInvalidFileAccess"))
|
|
{
|
|
pakLogFileAccess = sysPakLogInvalidAccess->GetIVal();
|
|
}
|
|
}
|
|
|
|
CTimeValue t0 = gEnv->pTimer->GetAsyncTime();
|
|
CryLog("-- Precaching textures...");
|
|
iLog->UpdateLoadingScreen(0);
|
|
|
|
std::vector<CTexture*> TexturesForPrecaching;
|
|
std::vector<CTexture*> TexturesForComposition;
|
|
|
|
bool bTextureCacheExists = false;
|
|
|
|
{
|
|
AUTO_LOCK(CBaseResource::s_cResLock);
|
|
|
|
SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
|
|
if (pRL)
|
|
{
|
|
TexturesForPrecaching.reserve(pRL->m_RMap.size());
|
|
|
|
ResourcesMapItor itor;
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
if (!tp)
|
|
{
|
|
continue;
|
|
}
|
|
if (tp->CTexture::IsPostponed())
|
|
{
|
|
if (tp->CTexture::GetFlags() & FT_COMPOSITE)
|
|
{
|
|
TexturesForComposition.push_back(tp);
|
|
}
|
|
else
|
|
{
|
|
TexturesForPrecaching.push_back(tp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Preload all the post poned textures
|
|
{
|
|
if (!gEnv->IsEditor())
|
|
{
|
|
CryLog("=============================== Loading textures ================================");
|
|
}
|
|
|
|
std::vector<CTexture*>& Textures = TexturesForPrecaching;
|
|
std::sort(Textures.begin(), Textures.end(), CompareTextures());
|
|
|
|
gEnv->pSystem->GetStreamEngine()->PauseStreaming(false, 1 << eStreamTaskTypeTexture);
|
|
|
|
for (uint32 i = 0; i < Textures.size(); i++)
|
|
{
|
|
CTexture* tp = Textures[i];
|
|
|
|
if (!CRenderer::CV_r_texturesstreaming || !tp->m_bStreamPrepared)
|
|
{
|
|
tp->m_bPostponed = false;
|
|
tp->Load(tp->m_eTFDst);
|
|
}
|
|
}
|
|
|
|
while (s_StreamPrepTasks.GetNumLive())
|
|
{
|
|
if (gRenDev->m_pRT->IsRenderThread() && !gRenDev->m_pRT->IsRenderLoadingThread())
|
|
{
|
|
StreamState_Update();
|
|
StreamState_UpdatePrep();
|
|
}
|
|
else if (gRenDev->m_pRT->IsRenderLoadingThread())
|
|
{
|
|
StreamState_UpdatePrep();
|
|
}
|
|
|
|
CrySleep(10);
|
|
}
|
|
|
|
for (uint32 i = 0; i < Textures.size(); i++)
|
|
{
|
|
CTexture* tp = Textures[i];
|
|
|
|
if (tp->m_bStreamed && tp->m_bForceStreamHighRes)
|
|
{
|
|
tp->m_bStreamHighPriority |= 1;
|
|
tp->m_fpMinMipCur = 0;
|
|
s_pTextureStreamer->Precache(tp);
|
|
}
|
|
}
|
|
|
|
if (!gEnv->IsEditor())
|
|
{
|
|
CryLog("========================== Finished loading textures ============================");
|
|
}
|
|
}
|
|
|
|
{
|
|
std::vector<CTexture*>& Textures = TexturesForComposition;
|
|
|
|
for (uint32 i = 0; i < Textures.size(); i++)
|
|
{
|
|
CTexture* tp = Textures[i];
|
|
|
|
if (!CRenderer::CV_r_texturesstreaming || !tp->m_bStreamPrepared)
|
|
{
|
|
tp->m_bPostponed = false;
|
|
tp->StreamPrepareComposition();
|
|
}
|
|
}
|
|
|
|
for (uint32 i = 0; i < Textures.size(); i++)
|
|
{
|
|
CTexture* tp = Textures[i];
|
|
|
|
if (tp->m_bStreamed && tp->m_bForceStreamHighRes)
|
|
{
|
|
tp->m_bStreamHighPriority |= 1;
|
|
tp->m_fpMinMipCur = 0;
|
|
s_pTextureStreamer->Precache(tp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bTextureCacheExists)
|
|
{
|
|
//GetISystem()->GetIResourceManager()->UnloadLevelCachePak( TEXTURE_LEVEL_CACHE_PAK );
|
|
}
|
|
|
|
CTimeValue t1 = gEnv->pTimer->GetAsyncTime();
|
|
float dt = (t1 - t0).GetSeconds();
|
|
CryLog("Precaching textures done in %.2f seconds", dt);
|
|
|
|
s_bPrecachePhase = false;
|
|
|
|
// Restore pakLogFileAccess if it was disabled during precaching
|
|
// because texture precaching was disabled
|
|
if (pakLogFileAccess)
|
|
{
|
|
sysPakLogInvalidAccess->Set(pakLogFileAccess);
|
|
}
|
|
}
|
|
|
|
bool CTexture::Load([[maybe_unused]] ETEX_Format eTFDst)
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION_NAMED_ARGS("CTexture::Load(ETEX_Format eTFDst)", m_SrcName.c_str());
|
|
m_bWasUnloaded = false;
|
|
m_bStreamed = false;
|
|
|
|
#if !defined(NULL_RENDERER)
|
|
bool bFound = LoadFromImage(m_SrcName.c_str(), eTFDst); // false=not reloading
|
|
#else
|
|
bool bFound = false;
|
|
#endif
|
|
|
|
if (!bFound)
|
|
{
|
|
SetNoTexture(m_eTT == eTT_Cube ? CTextureManager::Instance()->GetNoTextureCM() : CTextureManager::Instance()->GetNoTexture());
|
|
}
|
|
|
|
m_nFlags |= FT_FROMIMAGE;
|
|
PostCreate();
|
|
|
|
return bFound;
|
|
}
|
|
|
|
bool CTexture::ToggleStreaming(const bool bEnable)
|
|
{
|
|
if (!(m_nFlags & (FT_FROMIMAGE | FT_DONT_RELEASE)) || (m_nFlags & FT_DONT_STREAM))
|
|
{
|
|
return false;
|
|
}
|
|
AbortStreamingTasks(this);
|
|
if (bEnable)
|
|
{
|
|
if (IsStreamed())
|
|
{
|
|
return true;
|
|
}
|
|
ReleaseDeviceTexture(false);
|
|
m_bStreamed = true;
|
|
if (StreamPrepare(true))
|
|
{
|
|
return true;
|
|
}
|
|
if (m_pFileTexMips)
|
|
{
|
|
Unlink();
|
|
StreamState_ReleaseInfo(this, m_pFileTexMips);
|
|
m_pFileTexMips = NULL;
|
|
}
|
|
m_bStreamed = false;
|
|
if (m_bNoTexture)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
ReleaseDeviceTexture(false);
|
|
return Reload();
|
|
}
|
|
|
|
bool CTexture::LoadFromImage(const char* name, ETEX_Format eTFDst)
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION_ARGS(name);
|
|
|
|
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_texnoload)
|
|
{
|
|
if (SetNoTexture(CTextureManager::Instance()->GetNoTexture() ))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
string sFileName(name);
|
|
sFileName.MakeLower();
|
|
|
|
m_eTFDst = eTFDst;
|
|
|
|
// try to stream-in the texture
|
|
if (CRenderer::CV_r_texturesstreaming && !(m_nFlags & FT_DONT_STREAM) && (m_eTT == eTT_2D || m_eTT == eTT_Cube))
|
|
{
|
|
m_bStreamed = true;
|
|
if (StreamPrepare(true))
|
|
{
|
|
assert(m_pDevTexture);
|
|
return true;
|
|
}
|
|
m_nFlags |= FT_DONT_STREAM;
|
|
m_bStreamed = false;
|
|
m_bForceStreamHighRes = false;
|
|
if (m_bNoTexture)
|
|
{
|
|
if (m_pFileTexMips)
|
|
{
|
|
Unlink();
|
|
StreamState_ReleaseInfo(this, m_pFileTexMips);
|
|
m_pFileTexMips = NULL;
|
|
m_bStreamed = false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
#ifndef _RELEASE
|
|
CRY_DEFINE_ASSET_SCOPE("Texture", m_sAssetScopeName);
|
|
#endif
|
|
|
|
if (m_bPostponed)
|
|
{
|
|
if (s_pTextureStreamer->BeginPrepare(this, sFileName, (m_nFlags & FT_ALPHA) ? FIM_ALPHA : 0))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
uint32 nImageFlags = (m_nFlags & FT_ALPHA) ? FIM_ALPHA : 0;
|
|
|
|
if (I3DEngine* p3DEngine = gEnv->p3DEngine)
|
|
{
|
|
if (ITextureLoadHandler* pTextureHandler = p3DEngine->GetTextureLoadHandlerForImage(sFileName.c_str()))
|
|
{
|
|
STextureLoadData loadData;
|
|
loadData.m_pTexture = this;
|
|
loadData.m_nFlags = m_nFlags;
|
|
if (pTextureHandler->LoadTextureData(sFileName.c_str(), loadData))
|
|
{
|
|
bool bHasAlphaFlag = false;
|
|
|
|
//we must clear this or else our texture won't load properly
|
|
if ((m_nFlags & FT_ALPHA) == FT_ALPHA)
|
|
{
|
|
m_nFlags &= ~FT_ALPHA;
|
|
bHasAlphaFlag = true;
|
|
}
|
|
|
|
_smart_ptr<CImageFile> pImage = CImageFile::mfLoad_mem(sFileName, loadData.m_pData, loadData.m_Width, loadData.m_Height, loadData.m_Format, loadData.m_NumMips, loadData.m_nFlags);
|
|
m_bisTextureMissing = !pImage || pImage->mfGet_IsImageMissing();
|
|
loadData.m_pData = nullptr;
|
|
bool bLoadResult = Load(&*pImage);
|
|
|
|
if (bHasAlphaFlag)
|
|
{
|
|
m_nFlags |= FT_ALPHA;
|
|
}
|
|
|
|
return bLoadResult;
|
|
}
|
|
SetNoTexture(CTextureManager::Instance()->GetNoTexture() );
|
|
return true;
|
|
}
|
|
}
|
|
_smart_ptr<CImageFile> pImage = CImageFile::mfLoad_file(sFileName, nImageFlags);
|
|
m_bisTextureMissing = !pImage || pImage->mfGet_IsImageMissing();
|
|
return Load(pImage);
|
|
}
|
|
|
|
bool CTexture::Load([[maybe_unused]] CImageFile* pImage)
|
|
{
|
|
#if !defined(NULL_RENDERER)
|
|
if (!pImage || pImage->mfGetFormat() == eTF_Unknown)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LOADING_TIME_PROFILE_SECTION_NAMED_ARGS("CTexture::Load(CImageFile* pImage)", pImage->mfGet_filename().c_str());
|
|
|
|
// DHX-104: If this failed previously (maybe because the DDS was being generated), we must unset the failure flag
|
|
// so it doesn't appear to have failed again.
|
|
m_nFlags &= ~FT_FAILED;
|
|
if ((m_nFlags & FT_ALPHA) && !pImage->mfIs_image(0))
|
|
{
|
|
SetNoTexture( CTextureManager::Instance()->GetWhiteTexture() );
|
|
return true;
|
|
}
|
|
const char* name = pImage->mfGet_filename().c_str();
|
|
if (pImage->mfGet_Flags() & FIM_SPLITTED) // propagate splitted file flag
|
|
{
|
|
m_nFlags |= FT_SPLITTED;
|
|
}
|
|
if (pImage->mfGet_Flags() & FIM_X360_NOT_PRETILED)
|
|
{
|
|
m_nFlags |= FT_TEX_WAS_NOT_PRE_TILED;
|
|
}
|
|
if (pImage->mfGet_Flags() & FIM_NORMALMAP)
|
|
{
|
|
if (!(m_nFlags & FT_TEX_NORMAL_MAP) && !CryStringUtils::stristr(name, "_ddn"))
|
|
{
|
|
// becomes reported as editor error
|
|
gEnv->pSystem->Warning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE,
|
|
name, "Not a normal map texture attempted to be used as a normal map: %s", name);
|
|
}
|
|
}
|
|
|
|
if (!(m_nFlags & FT_ALPHA) && !(
|
|
pImage->mfGetFormat() == eTF_BC5U || pImage->mfGetFormat() == eTF_BC5S || pImage->mfGetFormat() == eTF_BC7 || pImage->mfGetFormat() == eTF_EAC_RG11
|
|
) && CryStringUtils::stristr(name, "_ddn") != 0 && GetDevTexture()) // improvable code
|
|
{
|
|
// becomes reported as editor error
|
|
gEnv->pSystem->Warning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE,
|
|
name, "Wrong format '%s' for normal map texture '%s'", CTexture::GetFormatName(), name);
|
|
}
|
|
|
|
if (pImage->mfGet_Flags() & FIM_NOTSUPPORTS_MIPS && !(m_nFlags & FT_NOMIPS))
|
|
{
|
|
m_nFlags |= FT_FORCE_MIPS;
|
|
}
|
|
if (pImage->mfGet_Flags() & FIM_HAS_ATTACHED_ALPHA)
|
|
{
|
|
m_nFlags |= FT_HAS_ATTACHED_ALPHA; // if the image has alpha attached we store this in the CTexture
|
|
}
|
|
m_eSrcTileMode = pImage->mfGetTileMode();
|
|
|
|
STexData td;
|
|
td.m_nFlags = pImage->mfGet_Flags();
|
|
td.m_pData[0] = pImage->mfGet_image(0);
|
|
td.m_nWidth = pImage->mfGet_width();
|
|
td.m_nHeight = pImage->mfGet_height();
|
|
td.m_nDepth = pImage->mfGet_depth();
|
|
td.m_eTF = pImage->mfGetFormat();
|
|
td.m_nMips = pImage->mfGet_numMips();
|
|
td.m_fAvgBrightness = pImage->mfGet_avgBrightness();
|
|
td.m_cMinColor = pImage->mfGet_minColor();
|
|
td.m_cMaxColor = pImage->mfGet_maxColor();
|
|
if ((m_nFlags & FT_NOMIPS) || td.m_nMips <= 0)
|
|
{
|
|
td.m_nMips = 1;
|
|
}
|
|
td.m_pFilePath = pImage->mfGet_filename();
|
|
|
|
// base range after normalization, fe. [0,1] for 8bit images, or [0,2^15] for RGBE/HDR data
|
|
if ((td.m_eTF == eTF_R9G9B9E5) || (td.m_eTF == eTF_BC6UH) || (td.m_eTF == eTF_BC6SH))
|
|
{
|
|
td.m_cMinColor /= td.m_cMaxColor.a;
|
|
td.m_cMaxColor /= td.m_cMaxColor.a;
|
|
}
|
|
|
|
// check if it's a cubemap
|
|
if (pImage->mfIs_image(1))
|
|
{
|
|
for (int i = 1; i < 6; i++)
|
|
{
|
|
td.m_pData[i] = pImage->mfGet_image(i);
|
|
}
|
|
}
|
|
|
|
bool bRes = false;
|
|
if (pImage)
|
|
{
|
|
FormatFixup(td);
|
|
bRes = CreateTexture(td);
|
|
}
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
if (td.m_pData[i] && td.WasReallocated(i))
|
|
{
|
|
SAFE_DELETE_ARRAY(td.m_pData[i]);
|
|
}
|
|
}
|
|
|
|
return bRes;
|
|
#else
|
|
SetNoTexture(CTextureManager::Instance()->GetWhiteTexture() );
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
bool CTexture::CreateTexture(STexData& td)
|
|
{
|
|
m_nWidth = td.m_nWidth;
|
|
m_nHeight = td.m_nHeight;
|
|
m_nDepth = td.m_nDepth;
|
|
m_eTFSrc = td.m_eTF;
|
|
m_nMips = td.m_nMips;
|
|
m_fAvgBrightness = td.m_fAvgBrightness;
|
|
m_cMinColor = td.m_cMinColor;
|
|
m_cMaxColor = td.m_cMaxColor;
|
|
m_cClearColor = ColorF(0.0f, 0.0f, 0.0f, 1.0f);
|
|
m_bUseDecalBorderCol = (td.m_nFlags & FIM_DECAL) != 0;
|
|
m_bIsSRGB = (td.m_nFlags & FIM_SRGB_READ) != 0;
|
|
|
|
assert(m_nWidth && m_nHeight && m_nMips);
|
|
|
|
if (td.m_pData[1] || (m_nFlags & FT_REPLICATE_TO_ALL_SIDES))
|
|
{
|
|
m_eTT = eTT_Cube;
|
|
}
|
|
else
|
|
{
|
|
if (m_nDepth > 1 || m_eTT == eTT_3D)
|
|
{
|
|
m_eTT = eTT_3D;
|
|
}
|
|
else
|
|
{
|
|
m_eTT = eTT_2D;
|
|
}
|
|
}
|
|
|
|
if (m_eTFDst == eTF_Unknown)
|
|
{
|
|
m_eTFDst = m_eTFSrc;
|
|
}
|
|
|
|
if (!ImagePreprocessing(td))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
assert(m_nWidth && m_nHeight && m_nMips);
|
|
|
|
const int nMaxTextureSize = gRenDev->GetMaxTextureSize();
|
|
if (nMaxTextureSize > 0)
|
|
{
|
|
if (m_nWidth > nMaxTextureSize || m_nHeight > nMaxTextureSize)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const byte* pData[6];
|
|
for (uint32 i = 0; i < 6; i++)
|
|
{
|
|
pData[i] = td.m_pData[i];
|
|
}
|
|
|
|
bool bRes = CreateDeviceTexture(pData);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
ETEX_Format CTexture::FormatFixup(ETEX_Format src)
|
|
{
|
|
switch (src)
|
|
{
|
|
case eTF_L8V8U8X8:
|
|
return eTF_R8G8B8A8S;
|
|
case eTF_B8G8R8:
|
|
return eTF_R8G8B8A8;
|
|
case eTF_L8V8U8:
|
|
return eTF_R8G8B8A8S;
|
|
case eTF_L8:
|
|
return eTF_R8G8B8A8;
|
|
case eTF_A8L8:
|
|
return eTF_R8G8B8A8;
|
|
|
|
case eTF_B5G5R5:
|
|
return eTF_R8G8B8A8;
|
|
case eTF_B5G6R5:
|
|
return eTF_R8G8B8A8;
|
|
case eTF_B4G4R4A4:
|
|
return eTF_R8G8B8A8;
|
|
|
|
default:
|
|
return src;
|
|
}
|
|
}
|
|
|
|
bool CTexture::FormatFixup(STexData& td)
|
|
{
|
|
const ETEX_Format targetFmt = FormatFixup(td.m_eTF);
|
|
|
|
if (m_eSrcTileMode == eTM_None)
|
|
{
|
|
// Try and expand
|
|
int nSourceSize = CTexture::TextureDataSize(td.m_nWidth, td.m_nHeight, td.m_nDepth, td.m_nMips, 1, td.m_eTF);
|
|
int nTargetSize = CTexture::TextureDataSize(td.m_nWidth, td.m_nHeight, td.m_nDepth, td.m_nMips, 1, targetFmt);
|
|
|
|
for (int nImage = 0; nImage < sizeof(td.m_pData) / sizeof(td.m_pData[0]); ++nImage)
|
|
{
|
|
if (td.m_pData[nImage])
|
|
{
|
|
byte* pNewImage = new byte[nTargetSize];
|
|
CTexture::ExpandMipFromFile(pNewImage, nTargetSize, td.m_pData[nImage], nSourceSize, td.m_eTF);
|
|
td.AssignData(nImage, pNewImage);
|
|
}
|
|
}
|
|
|
|
td.m_eTF = targetFmt;
|
|
}
|
|
else
|
|
{
|
|
#ifndef _RELEASE
|
|
if (targetFmt != td.m_eTF)
|
|
{
|
|
__debugbreak();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CTexture::ImagePreprocessing(STexData& td)
|
|
{
|
|
FUNCTION_PROFILER_FAST(GetISystem(), PROFILE_RENDERER, g_bProfilerEnabled);
|
|
|
|
const char* pTexFileName = td.m_pFilePath ? td.m_pFilePath : "$Unknown";
|
|
|
|
const ETEX_Format eTFDst = ClosestFormatSupported(m_eTFDst);
|
|
if (eTFDst == eTF_Unknown)
|
|
{
|
|
td.m_pData[0] = td.m_pData[1] = td.m_pData[2] = td.m_pData[3] = td.m_pData[4] = td.m_pData[5] = 0;
|
|
m_nWidth = m_nHeight = m_nDepth = m_nMips = 0;
|
|
|
|
#if !defined(_RELEASE)
|
|
TextureError(pTexFileName, "Trying to create a texture with unsupported target format %s!", NameForTextureFormat(eTFDst));
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
const ETEX_Format eTF = td.m_eTF;
|
|
const bool fmtConversionNeeded = eTFDst != m_eTFDst || eTF != eTFDst;
|
|
|
|
#if !(defined(WIN32) || defined(WIN64)) || defined(OPENGL) || defined(NULL_RENDERER)
|
|
if (fmtConversionNeeded)
|
|
{
|
|
td.m_pData[0] = td.m_pData[1] = td.m_pData[2] = td.m_pData[3] = td.m_pData[4] = td.m_pData[5] = 0;
|
|
m_nWidth = m_nHeight = m_nDepth = m_nMips = 0;
|
|
|
|
# if !defined(_RELEASE)
|
|
TextureError(pTexFileName, "Trying an image format conversion from %s to %s. This is not supported on this platform!", NameForTextureFormat(eTF), NameForTextureFormat(eTFDst));
|
|
# endif
|
|
return false;
|
|
}
|
|
#else
|
|
const bool doProcessing = fmtConversionNeeded && (m_nFlags & FT_TEX_FONT) == 0; // we generate the font in native format
|
|
if (doProcessing)
|
|
{
|
|
m_eTFSrc = eTFDst;
|
|
m_eTFDst = eTFDst;
|
|
|
|
const int nSrcWidth = td.m_nWidth;
|
|
const int nSrcHeight = td.m_nHeight;
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
const byte* pTexData = td.m_pData[i];
|
|
if (pTexData)
|
|
{
|
|
int nOutSize = 0;
|
|
const byte* pNewData = Convert(pTexData, nSrcWidth, nSrcHeight, td.m_nMips, eTF, eTFDst, nOutSize, true);
|
|
if (pNewData)
|
|
{
|
|
td.AssignData(i, pNewData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(TEXTURE_GET_SYSTEM_COPY_SUPPORT) && !defined(NULL_RENDERER)
|
|
if (m_nFlags & FT_KEEP_LOWRES_SYSCOPY)
|
|
{
|
|
PrepareLowResSystemCopy(td.m_pData[0], true);
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
int CTexture::CalcNumMips(int nWidth, int nHeight)
|
|
{
|
|
int nMips = 0;
|
|
while (nWidth || nHeight)
|
|
{
|
|
if (!nWidth)
|
|
{
|
|
nWidth = 1;
|
|
}
|
|
if (!nHeight)
|
|
{
|
|
nHeight = 1;
|
|
}
|
|
nWidth >>= 1;
|
|
nHeight >>= 1;
|
|
nMips++;
|
|
}
|
|
//For DX11 hardware, the number of mips must be between 1 and 7, inclusive
|
|
//0 is a valid result but means that D3D11 will generate a full series of mipmaps
|
|
if (nMips > 7)
|
|
{
|
|
return 7;
|
|
}
|
|
|
|
return nMips;
|
|
}
|
|
|
|
uint32 CTexture::TextureDataSize(uint32 nWidth, uint32 nHeight, uint32 nDepth, uint32 nMips, uint32 nSlices, const ETEX_Format eTF, ETEX_TileMode eTM)
|
|
{
|
|
if (eTF == eTF_Unknown)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (eTM != eTM_None)
|
|
{
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION TEXTURE_CPP_SECTION_2
|
|
#include AZ_RESTRICTED_FILE(Texture_cpp)
|
|
#endif
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION TEXTURE_CPP_SECTION_3
|
|
#include AZ_RESTRICTED_FILE(Texture_cpp)
|
|
#endif
|
|
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
const Vec2i BlockDim = GetBlockDim(eTF);
|
|
const int nBytesPerBlock = CImageExtensionHelper::BytesPerBlock(eTF);
|
|
uint32 nSize = 0;
|
|
|
|
while ((nWidth || nHeight || nDepth) && nMips)
|
|
{
|
|
nWidth = max(1U, nWidth);
|
|
nHeight = max(1U, nHeight);
|
|
nDepth = max(1U, nDepth);
|
|
|
|
nSize += ((nWidth + BlockDim.x - 1) / BlockDim.x) * ((nHeight + BlockDim.y - 1) / BlockDim.y) * nDepth * nBytesPerBlock;
|
|
|
|
nWidth >>= 1;
|
|
nHeight >>= 1;
|
|
nDepth >>= 1;
|
|
--nMips;
|
|
}
|
|
|
|
return nSize * nSlices;
|
|
}
|
|
}
|
|
|
|
bool CTexture::IsInPlaceFormat(const ETEX_Format fmt)
|
|
{
|
|
switch (fmt)
|
|
{
|
|
case eTF_R8G8B8A8S:
|
|
case eTF_R8G8B8A8:
|
|
|
|
case eTF_A8:
|
|
case eTF_R8:
|
|
case eTF_R8S:
|
|
case eTF_R16:
|
|
case eTF_R16U:
|
|
case eTF_R16G16U:
|
|
case eTF_R10G10B10A2UI:
|
|
case eTF_R16F:
|
|
case eTF_R32F:
|
|
case eTF_R8G8:
|
|
case eTF_R8G8S:
|
|
case eTF_R16G16:
|
|
case eTF_R16G16S:
|
|
case eTF_R16G16F:
|
|
case eTF_R11G11B10F:
|
|
case eTF_R10G10B10A2:
|
|
case eTF_R16G16B16A16:
|
|
case eTF_R16G16B16A16S:
|
|
case eTF_R16G16B16A16F:
|
|
case eTF_R32G32B32A32F:
|
|
|
|
case eTF_CTX1:
|
|
case eTF_BC1:
|
|
case eTF_BC2:
|
|
case eTF_BC3:
|
|
case eTF_BC4U:
|
|
case eTF_BC4S:
|
|
case eTF_BC5U:
|
|
case eTF_BC5S:
|
|
#if defined(CRY_DDS_DX10_SUPPORT)
|
|
case eTF_BC6UH:
|
|
case eTF_BC6SH:
|
|
case eTF_BC7:
|
|
case eTF_R9G9B9E5:
|
|
#endif
|
|
case eTF_EAC_R11:
|
|
case eTF_EAC_RG11:
|
|
case eTF_ETC2:
|
|
case eTF_ETC2A:
|
|
|
|
case eTF_B8G8R8A8:
|
|
case eTF_B8G8R8X8:
|
|
#ifdef CRY_USE_METAL
|
|
case eTF_PVRTC2:
|
|
case eTF_PVRTC4:
|
|
#endif
|
|
#if defined(ANDROID) || defined(CRY_USE_METAL)
|
|
case eTF_ASTC_4x4:
|
|
case eTF_ASTC_5x4:
|
|
case eTF_ASTC_5x5:
|
|
case eTF_ASTC_6x5:
|
|
case eTF_ASTC_6x6:
|
|
case eTF_ASTC_8x5:
|
|
case eTF_ASTC_8x6:
|
|
case eTF_ASTC_8x8:
|
|
case eTF_ASTC_10x5:
|
|
case eTF_ASTC_10x6:
|
|
case eTF_ASTC_10x8:
|
|
case eTF_ASTC_10x10:
|
|
case eTF_ASTC_12x10:
|
|
case eTF_ASTC_12x12:
|
|
#endif
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void CTexture::ExpandMipFromFile(byte* dest, [[maybe_unused]] const int destSize, const byte* src, const int srcSize, const ETEX_Format fmt)
|
|
{
|
|
if (IsInPlaceFormat(fmt))
|
|
{
|
|
assert(destSize == srcSize);
|
|
if (dest != src)
|
|
{
|
|
cryMemcpy(dest, src, srcSize);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// upload mip from file with conversions depending on format and platform specifics
|
|
switch (fmt)
|
|
{
|
|
case eTF_B8G8R8:
|
|
for (int i = srcSize / 3 - 1; i >= 0; --i)
|
|
{
|
|
dest[i * 4 + 0] = src[i * 3 + 2];
|
|
dest[i * 4 + 1] = src[i * 3 + 1];
|
|
dest[i * 4 + 2] = src[i * 3 + 0];
|
|
dest[i * 4 + 3] = 255;
|
|
}
|
|
break;
|
|
case eTF_L8V8U8X8:
|
|
assert(destSize == srcSize);
|
|
if (dest != src)
|
|
{
|
|
cryMemcpy(dest, src, srcSize);
|
|
}
|
|
for (int i = srcSize / 4 - 1; i >= 0; --i)
|
|
{
|
|
dest[i * 4 + 0] = src[i * 3 + 0];
|
|
dest[i * 4 + 1] = src[i * 3 + 1];
|
|
dest[i * 4 + 2] = src[i * 3 + 2];
|
|
dest[i * 4 + 3] = src[i * 3 + 3];
|
|
}
|
|
break;
|
|
case eTF_L8V8U8:
|
|
for (int i = srcSize / 3 - 1; i >= 0; --i)
|
|
{
|
|
dest[i * 4 + 0] = src[i * 3 + 0];
|
|
dest[i * 4 + 1] = src[i * 3 + 1];
|
|
dest[i * 4 + 2] = src[i * 3 + 2];
|
|
dest[i * 4 + 3] = 255;
|
|
}
|
|
break;
|
|
case eTF_L8:
|
|
for (int i = srcSize - 1; i >= 0; --i)
|
|
{
|
|
const byte bSrc = src[i];
|
|
dest[i * 4 + 0] = bSrc;
|
|
dest[i * 4 + 1] = bSrc;
|
|
dest[i * 4 + 2] = bSrc;
|
|
dest[i * 4 + 3] = 255;
|
|
}
|
|
break;
|
|
case eTF_A8L8:
|
|
for (int i = srcSize - 1; i >= 0; i -= 2)
|
|
{
|
|
const byte bSrcL = src[i - 1];
|
|
const byte bSrcA = src[i - 0];
|
|
dest[i * 4 + 0] = bSrcL;
|
|
dest[i * 4 + 1] = bSrcL;
|
|
dest[i * 4 + 2] = bSrcL;
|
|
dest[i * 4 + 3] = bSrcA;
|
|
}
|
|
break;
|
|
case eTF_B5G5R5:
|
|
case eTF_B5G6R5:
|
|
case eTF_B4G4R4A4:
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
bool CTexture::Invalidate(int nNewWidth, int nNewHeight, ETEX_Format eTF)
|
|
{
|
|
bool bRelease = false;
|
|
if (nNewWidth > 0 && nNewWidth != m_nWidth)
|
|
{
|
|
m_nWidth = nNewWidth;
|
|
bRelease = true;
|
|
}
|
|
if (nNewHeight > 0 && nNewHeight != m_nHeight)
|
|
{
|
|
m_nHeight = nNewHeight;
|
|
bRelease = true;
|
|
}
|
|
if (eTF != eTF_Unknown && eTF != m_eTFDst)
|
|
{
|
|
m_eTFDst = eTF;
|
|
bRelease = true;
|
|
}
|
|
|
|
if (!m_pDevTexture)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (bRelease)
|
|
{
|
|
if (m_nFlags & FT_FORCE_MIPS)
|
|
{
|
|
m_nMips = 1;
|
|
}
|
|
|
|
ReleaseDeviceTexture(true);
|
|
}
|
|
|
|
return bRelease;
|
|
}
|
|
|
|
SResourceView& CTexture::GetResourceView(const SResourceView& rvDesc)
|
|
{
|
|
assert(m_pRenderTargetData);
|
|
|
|
int nIndex = m_pRenderTargetData->m_ResourceViews.Find(rvDesc);
|
|
|
|
if (nIndex < 0)
|
|
{
|
|
SResourceView* pRvDesc = m_pRenderTargetData->m_ResourceViews.AddIndex(1);
|
|
pRvDesc->m_Desc = rvDesc.m_Desc;
|
|
pRvDesc->m_pDeviceResourceView = CreateDeviceResourceView(rvDesc);
|
|
|
|
nIndex = m_pRenderTargetData->m_ResourceViews.size() - 1;
|
|
}
|
|
|
|
return m_pRenderTargetData->m_ResourceViews[nIndex];
|
|
}
|
|
|
|
D3DShaderResourceView* CTexture::GetShaderResourceView(SResourceView::KeyType resourceViewID /*= SResourceView::DefaultView*/, bool bLegacySrgbLookup /*= false*/)
|
|
{
|
|
if ((int64)resourceViewID <= (int64)SResourceView::DefaultView)
|
|
{
|
|
void* pResult = m_pDeviceShaderResource;
|
|
|
|
if (resourceViewID == SResourceView::DefaultViewMS && m_pRenderTargetData && m_pRenderTargetData->m_pDeviceTextureMSAA)
|
|
{
|
|
SResourceView& pMultisampledRV = GetResourceView(SResourceView::ShaderResourceView(m_eTFDst, 0, -1, 0, -1, false, true));
|
|
pResult = pMultisampledRV.m_pDeviceResourceView;
|
|
}
|
|
|
|
// NOTE: "m_pDeviceShaderResourceSRGB != nullptr" implies FT_USAGE_ALLOWREADSRGB
|
|
if ((resourceViewID == SResourceView::DefaultViewSRGB || bLegacySrgbLookup) && m_pDeviceShaderResourceSRGB)
|
|
{
|
|
pResult = m_pDeviceShaderResourceSRGB;
|
|
}
|
|
|
|
return (D3DShaderResourceView*)pResult;
|
|
}
|
|
else
|
|
{
|
|
return (D3DShaderResourceView*)GetResourceView(resourceViewID).m_pDeviceResourceView;
|
|
}
|
|
}
|
|
|
|
void CTexture::SetShaderResourceView(D3DShaderResourceView* pDeviceShaderResource, bool bMultisampled)
|
|
{
|
|
if (bMultisampled && m_pRenderTargetData && m_pRenderTargetData->m_pDeviceTextureMSAA)
|
|
{
|
|
SResourceView& pMultisampledRV = GetResourceView(SResourceView::ShaderResourceView(m_eTFDst, 0, -1, 0, -1, false, true));
|
|
|
|
if (pMultisampledRV.m_pDeviceResourceView != pDeviceShaderResource)
|
|
{
|
|
pMultisampledRV.m_pDeviceResourceView = pDeviceShaderResource;
|
|
InvalidateDeviceResource(eDeviceResourceViewDirty);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_pDeviceShaderResource != pDeviceShaderResource)
|
|
{
|
|
m_pDeviceShaderResource = pDeviceShaderResource;
|
|
InvalidateDeviceResource(eDeviceResourceViewDirty);
|
|
}
|
|
}
|
|
}
|
|
|
|
D3DUnorderedAccessView* CTexture::GetDeviceUAV()
|
|
{
|
|
const SResourceView& rvDesc = m_pRenderTargetData ? GetResourceView(SResourceView::UnorderedAccessView(m_eTFDst, 0, -1, 0, m_nFlags)) : NULL;
|
|
return (D3DUnorderedAccessView*)rvDesc.m_pDeviceResourceView;
|
|
}
|
|
|
|
D3DDepthSurface* CTexture::GetDeviceDepthStencilSurf(int nFirstSlice, int nSliceCount)
|
|
{
|
|
const SResourceView& rvDesc = GetResourceView(SResourceView::DepthStencilView(m_eTFDst, nFirstSlice, nSliceCount));
|
|
return (D3DDepthSurface*)rvDesc.m_pDeviceResourceView;
|
|
}
|
|
|
|
byte* CTexture::GetData32([[maybe_unused]] int nSide, [[maybe_unused]] int nLevel, [[maybe_unused]] byte* pDst, [[maybe_unused]] ETEX_Format eDstFormat)
|
|
{
|
|
#if (defined(WIN32) || defined(WIN64)) && !defined(NULL_RENDERER)
|
|
CDeviceTexture* pDevTexture = GetDevTexture();
|
|
pDevTexture->DownloadToStagingResource(D3D11CalcSubresource(nLevel, nSide, m_nMips), [&](void* pData, [[maybe_unused]] uint32 rowPitch, [[maybe_unused]] uint32 slicePitch)
|
|
{
|
|
if (m_eTFDst != eTF_R8G8B8A8)
|
|
{
|
|
int nOutSize = 0;
|
|
|
|
if (m_eTFSrc == eDstFormat && pDst)
|
|
{
|
|
memcpy(pDst, pData, GetDeviceDataSize());
|
|
}
|
|
else
|
|
{
|
|
pDst = Convert((byte*)pData, m_nWidth, m_nHeight, 1, m_eTFSrc, eDstFormat, nOutSize, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!pDst)
|
|
{
|
|
pDst = new byte[m_nWidth * m_nHeight * 4];
|
|
}
|
|
|
|
memcpy(pDst, pData, m_nWidth * m_nHeight * 4);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
return pDst;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
const int CTexture::GetSize(bool bIncludePool) const
|
|
{
|
|
int nSize = sizeof(CTexture);
|
|
nSize += m_SrcName.capacity();
|
|
if (m_pRenderTargetData)
|
|
{
|
|
nSize += sizeof(*m_pRenderTargetData);
|
|
}
|
|
if (m_pFileTexMips)
|
|
{
|
|
nSize += m_pFileTexMips->GetSize(m_nMips, m_CacheFileHeader.m_nSides);
|
|
if (bIncludePool && m_pFileTexMips->m_pPoolItem)
|
|
{
|
|
nSize += m_pFileTexMips->m_pPoolItem->GetSize();
|
|
}
|
|
}
|
|
|
|
return nSize;
|
|
}
|
|
|
|
void CTexture::Init()
|
|
{
|
|
SDynTexture::Init();
|
|
InitStreaming();
|
|
CTexture::s_TexStates.reserve(300); // this likes to expand, so it'd be nice if it didn't; 300 => ~6Kb, there were 171 after one level
|
|
|
|
SDynTexture2::Init(eTP_Clouds);
|
|
}
|
|
|
|
void CTexture::PostInit()
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION;
|
|
if (!gRenDev->IsShaderCacheGenMode())
|
|
{
|
|
CTexture::LoadDefaultSystemTextures();
|
|
}
|
|
}
|
|
|
|
int __cdecl TexCallback(const VOID * arg1, const VOID * arg2)
|
|
{
|
|
CTexture** pi1 = (CTexture**)arg1;
|
|
CTexture** pi2 = (CTexture**)arg2;
|
|
CTexture* ti1 = *pi1;
|
|
CTexture* ti2 = *pi2;
|
|
|
|
if (ti1->GetDeviceDataSize() > ti2->GetDeviceDataSize())
|
|
{
|
|
return -1;
|
|
}
|
|
if (ti1->GetDeviceDataSize() < ti2->GetDeviceDataSize())
|
|
{
|
|
return 1;
|
|
}
|
|
return azstricmp(ti1->GetSourceName(), ti2->GetSourceName());
|
|
}
|
|
|
|
int __cdecl TexCallbackMips(const VOID * arg1, const VOID * arg2)
|
|
{
|
|
CTexture** pi1 = (CTexture**)arg1;
|
|
CTexture** pi2 = (CTexture**)arg2;
|
|
CTexture* ti1 = *pi1;
|
|
CTexture* ti2 = *pi2;
|
|
|
|
int nSize1, nSize2;
|
|
|
|
nSize1 = ti1->GetActualSize();
|
|
nSize2 = ti2->GetActualSize();
|
|
|
|
if (nSize1 > nSize2)
|
|
{
|
|
return -1;
|
|
}
|
|
if (nSize1 < nSize2)
|
|
{
|
|
return 1;
|
|
}
|
|
return azstricmp(ti1->GetSourceName(), ti2->GetSourceName());
|
|
}
|
|
|
|
void CTexture::Update()
|
|
{
|
|
FUNCTION_PROFILER_RENDERER;
|
|
|
|
CRenderer* rd = gRenDev;
|
|
char buf[256] = "";
|
|
|
|
// reload pending texture reload requests
|
|
{
|
|
AZStd::set<string, AZStd::less<string>, AZ::StdLegacyAllocator> queue;
|
|
|
|
s_xTexReloadLock.Lock();
|
|
s_vTexReloadRequests.swap(queue);
|
|
s_xTexReloadLock.Unlock();
|
|
|
|
for (auto i = queue.begin(); i != queue.end(); i++)
|
|
{
|
|
ReloadFile(*i);
|
|
}
|
|
}
|
|
|
|
CTexture::s_bStreamingFromHDD = gEnv->pSystem->GetStreamEngine()->IsStreamDataOnHDD();
|
|
CTexture::s_nStatsStreamPoolInUseMem = CTexture::s_pPoolMgr->GetInUseSize();
|
|
|
|
s_pTextureStreamer->ApplySchedule(ITextureStreamer::eASF_Full);
|
|
s_pTextureStreamer->BeginUpdateSchedule();
|
|
|
|
#ifdef ENABLE_TEXTURE_STREAM_LISTENER
|
|
StreamUpdateStats();
|
|
#endif
|
|
|
|
SDynTexture::Tick();
|
|
|
|
SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
|
|
ResourcesMapItor itor;
|
|
|
|
if ((s_nStreamingMode != CRenderer::CV_r_texturesstreaming) || (s_nStreamingUpdateMode != CRenderer::CV_r_texturesstreamingUpdateType))
|
|
{
|
|
InitStreaming();
|
|
}
|
|
|
|
if (pRL)
|
|
{
|
|
#ifndef CONSOLE_CONST_CVAR_MODE
|
|
uint32 i;
|
|
if (CRenderer::CV_r_texlog == 2 || CRenderer::CV_r_texlog == 3 || CRenderer::CV_r_texlog == 4)
|
|
{
|
|
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
|
|
TArray<CTexture*> Texs;
|
|
int Size = 0;
|
|
int PartSize = 0;
|
|
if (CRenderer::CV_r_texlog == 2 || CRenderer::CV_r_texlog == 3)
|
|
{
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
if (CRenderer::CV_r_texlog == 3 && tp->IsNoTexture())
|
|
{
|
|
Texs.AddElem(tp);
|
|
}
|
|
else
|
|
if (CRenderer::CV_r_texlog == 2 && !tp->IsNoTexture() && tp->m_pFileTexMips) // (tp->GetFlags() & FT_FROMIMAGE))
|
|
{
|
|
Texs.AddElem(tp);
|
|
}
|
|
}
|
|
if (CRenderer::CV_r_texlog == 3)
|
|
{
|
|
CryLogAlways("Logging to MissingTextures.txt...");
|
|
fileHandle = fxopen("MissingTextures.txt", "w");
|
|
}
|
|
else
|
|
{
|
|
CryLogAlways("Logging to UsedTextures.txt...");
|
|
fileHandle = fxopen("UsedTextures.txt", "w");
|
|
}
|
|
AZ::IO::Print(fileHandle, "*** All textures: ***\n");
|
|
|
|
if (Texs.Num())
|
|
{
|
|
qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallbackMips);
|
|
}
|
|
|
|
for (i = 0; i < Texs.Num(); i++)
|
|
{
|
|
int w = Texs[i]->GetWidth();
|
|
int h = Texs[i]->GetHeight();
|
|
|
|
int nTSize = Texs[i]->m_pFileTexMips->GetSize(Texs[i]->GetNumMips(), Texs[i]->GetNumSides());
|
|
|
|
AZ::IO::Print(fileHandle, "%d\t\t%d x %d\t\tType: %s\t\tMips: %d\t\tFormat: %s\t\t(%s)\n", nTSize, w, h, Texs[i]->NameForTextureType(Texs[i]->GetTextureType()), Texs[i]->GetNumMips(), Texs[i]->NameForTextureFormat(Texs[i]->GetDstFormat()), Texs[i]->GetName());
|
|
//Size += Texs[i]->GetDataSize();
|
|
Size += nTSize;
|
|
|
|
PartSize += Texs[i]->GetDeviceDataSize();
|
|
}
|
|
AZ::IO::Print(fileHandle, "*** Total Size: %d\n\n", Size /*, PartSize, PartSize */);
|
|
|
|
Texs.Free();
|
|
}
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
if (tp->m_nAccessFrameID == rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_nFrameUpdateID)
|
|
{
|
|
Texs.AddElem(tp);
|
|
}
|
|
}
|
|
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
gEnv->pFileIO->Close(fileHandle);
|
|
fileHandle = AZ::IO::InvalidHandle;
|
|
}
|
|
|
|
fileHandle = fxopen("UsedTextures_Frame.txt", "w");
|
|
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
AZ::IO::Print(fileHandle, "\n\n*** Textures used in current frame: ***\n");
|
|
}
|
|
else
|
|
{
|
|
rd->TextToScreenColor(4, 13, 1, 1, 0, 1, "*** Textures used in current frame: ***");
|
|
}
|
|
int nY = 17;
|
|
|
|
if (Texs.Num())
|
|
{
|
|
qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallback);
|
|
}
|
|
|
|
Size = 0;
|
|
for (i = 0; i < Texs.Num(); i++)
|
|
{
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
AZ::IO::Print(fileHandle, "%.3fKb\t\tType: %s\t\tFormat: %s\t\t(%s)\n", Texs[i]->GetDeviceDataSize() / 1024.0f, CTexture::NameForTextureType(Texs[i]->GetTextureType()), CTexture::NameForTextureFormat(Texs[i]->GetDstFormat()), Texs[i]->GetName());
|
|
}
|
|
else
|
|
{
|
|
sprintf_s(buf, "%.3fKb Type: %s Format: %s (%s)", Texs[i]->GetDeviceDataSize() / 1024.0f, CTexture::NameForTextureType(Texs[i]->GetTextureType()), CTexture::NameForTextureFormat(Texs[i]->GetDstFormat()), Texs[i]->GetName());
|
|
rd->TextToScreenColor(4, nY, 0, 1, 0, 1, buf);
|
|
nY += 3;
|
|
}
|
|
PartSize += Texs[i]->GetDeviceDataSize();
|
|
Size += Texs[i]->GetDataSize();
|
|
}
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
AZ::IO::Print(fileHandle, "*** Total Size: %.3fMb, Device Size: %.3fMb\n\n", Size / (1024.0f * 1024.0f), PartSize / (1024.0f * 1024.0f));
|
|
}
|
|
else
|
|
{
|
|
sprintf_s(buf, "*** Total Size: %.3fMb, Device Size: %.3fMb", Size / (1024.0f * 1024.0f), PartSize / (1024.0f * 1024.0f));
|
|
rd->TextToScreenColor(4, nY + 1, 0, 1, 1, 1, buf);
|
|
}
|
|
|
|
Texs.Free();
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
if (tp && !tp->IsNoTexture())
|
|
{
|
|
Texs.AddElem(tp);
|
|
}
|
|
}
|
|
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
gEnv->pFileIO->Close(fileHandle);
|
|
fileHandle = AZ::IO::InvalidHandle;
|
|
}
|
|
fileHandle = fxopen("UsedTextures_All.txt", "w");
|
|
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
AZ::IO::Print(fileHandle, "\n\n*** All Existing Textures: ***\n");
|
|
}
|
|
else
|
|
{
|
|
rd->TextToScreenColor(4, 13, 1, 1, 0, 1, "*** Textures loaded: ***");
|
|
}
|
|
|
|
if (Texs.Num())
|
|
{
|
|
qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallback);
|
|
}
|
|
|
|
Size = 0;
|
|
for (i = 0; i < Texs.Num(); i++)
|
|
{
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
int w = Texs[i]->GetWidth();
|
|
int h = Texs[i]->GetHeight();
|
|
AZ::IO::Print(fileHandle, "%d\t\t%d x %d\t\t%d mips (%.3fKb)\t\tType: %s \t\tFormat: %s\t\t(%s)\n", Texs[i]->GetDataSize(), w, h, Texs[i]->GetNumMips(), Texs[i]->GetDeviceDataSize() / 1024.0f, CTexture::NameForTextureType(Texs[i]->GetTextureType()), CTexture::NameForTextureFormat(Texs[i]->GetDstFormat()), Texs[i]->GetName());
|
|
}
|
|
else
|
|
{
|
|
sprintf_s(buf, "%.3fKb Type: %s Format: %s (%s)", Texs[i]->GetDataSize() / 1024.0f, CTexture::NameForTextureType(Texs[i]->GetTextureType()), CTexture::NameForTextureFormat(Texs[i]->GetDstFormat()), Texs[i]->GetName());
|
|
rd->TextToScreenColor(4, nY, 0, 1, 0, 1, buf);
|
|
nY += 3;
|
|
}
|
|
Size += Texs[i]->GetDeviceDataSize();
|
|
}
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
AZ::IO::Print(fileHandle, "*** Total Size: %.3fMb\n\n", Size / (1024.0f * 1024.0f));
|
|
}
|
|
else
|
|
{
|
|
sprintf_s(buf, "*** Total Size: %.3fMb", Size / (1024.0f * 1024.0f));
|
|
rd->TextToScreenColor(4, nY + 1, 0, 1, 1, 1, buf);
|
|
}
|
|
|
|
|
|
Texs.Free();
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
if (tp && !tp->IsNoTexture() && !tp->IsStreamed())
|
|
{
|
|
Texs.AddElem(tp);
|
|
}
|
|
}
|
|
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
gEnv->pFileIO->Close(fileHandle);
|
|
fileHandle = AZ::IO::InvalidHandle;
|
|
}
|
|
|
|
if (CRenderer::CV_r_texlog != 4)
|
|
{
|
|
CRenderer::CV_r_texlog = 0;
|
|
}
|
|
}
|
|
else
|
|
if (CRenderer::CV_r_texlog == 1)
|
|
{
|
|
//char *str = GetTexturesStatusText();
|
|
|
|
TArray<CTexture*> Texs;
|
|
//TArray<CTexture *> TexsNM;
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
if (tp && !tp->IsNoTexture())
|
|
{
|
|
Texs.AddElem(tp);
|
|
//if (tp->GetFlags() & FT_TEX_NORMAL_MAP)
|
|
// TexsNM.AddElem(tp);
|
|
}
|
|
}
|
|
|
|
if (Texs.Num())
|
|
{
|
|
qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallback);
|
|
}
|
|
|
|
int64 AllSize = 0;
|
|
int64 Size = 0;
|
|
int64 PartSize = 0;
|
|
int64 NonStrSize = 0;
|
|
int nNoStr = 0;
|
|
int64 SizeNM = 0;
|
|
int64 SizeDynCom = 0;
|
|
int64 SizeDynAtl = 0;
|
|
int64 PartSizeNM = 0;
|
|
int nNumTex = 0;
|
|
int nNumTexNM = 0;
|
|
int nNumTexDynAtl = 0;
|
|
int nNumTexDynCom = 0;
|
|
for (i = 0; i < Texs.Num(); i++)
|
|
{
|
|
CTexture* tex = Texs[i];
|
|
const uint32 texFlags = tex->GetFlags();
|
|
const int texDataSize = tex->GetDataSize();
|
|
const int texDeviceDataSize = tex->GetDeviceDataSize();
|
|
|
|
if (tex->GetDevTexture() && !(texFlags & (FT_USAGE_DYNAMIC | FT_USAGE_RENDERTARGET)))
|
|
{
|
|
AllSize += texDataSize;
|
|
if (!Texs[i]->IsStreamed())
|
|
{
|
|
NonStrSize += texDataSize;
|
|
nNoStr++;
|
|
}
|
|
}
|
|
|
|
if (texFlags & (FT_USAGE_RENDERTARGET | FT_USAGE_DYNAMIC))
|
|
{
|
|
if (texFlags & FT_USAGE_ATLAS)
|
|
{
|
|
++nNumTexDynAtl;
|
|
SizeDynAtl += texDataSize;
|
|
}
|
|
else
|
|
{
|
|
++nNumTexDynCom;
|
|
SizeDynCom += texDataSize;
|
|
}
|
|
}
|
|
else
|
|
if (0 == (texFlags & FT_TEX_NORMAL_MAP))
|
|
{
|
|
if (!Texs[i]->IsUnloaded())
|
|
{
|
|
++nNumTex;
|
|
Size += texDataSize;
|
|
PartSize += texDeviceDataSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!Texs[i]->IsUnloaded())
|
|
{
|
|
++nNumTexNM;
|
|
SizeNM += texDataSize;
|
|
PartSizeNM += texDeviceDataSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
sprintf_s(buf, "All texture objects: %d (Size: %.3fMb), NonStreamed: %d (Size: %.3fMb)", Texs.Num(), AllSize / (1024.0 * 1024.0), nNoStr, NonStrSize / (1024.0 * 1024.0));
|
|
rd->TextToScreenColor(4, 13, 1, 1, 0, 1, buf);
|
|
sprintf_s(buf, "All Loaded Texture Maps: %d (All MIPS: %.3fMb, Loaded MIPS: %.3fMb)", nNumTex, Size / (1024.0f * 1024.0f), PartSize / (1024.0 * 1024.0));
|
|
rd->TextToScreenColor(4, 16, 1, 1, 0, 1, buf);
|
|
sprintf_s(buf, "All Loaded Normal Maps: %d (All MIPS: %.3fMb, Loaded MIPS: %.3fMb)", nNumTexNM, SizeNM / (1024.0 * 1024.0), PartSizeNM / (1024.0 * 1024.0));
|
|
rd->TextToScreenColor(4, 19, 1, 1, 0, 1, buf);
|
|
sprintf_s(buf, "All Dynamic textures: %d (%.3fMb), %d Atlases (%.3fMb), %d Separared (%.3fMb)", nNumTexDynAtl + nNumTexDynCom, (SizeDynAtl + SizeDynCom) / (1024.0 * 1024.0), nNumTexDynAtl, SizeDynAtl / (1024.0 * 1024.0), nNumTexDynCom, SizeDynCom / (1024.0 * 1024.0));
|
|
rd->TextToScreenColor(4, 22, 1, 1, 0, 1, buf);
|
|
|
|
Texs.Free();
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
if (tp && !tp->IsNoTexture() && tp->m_nAccessFrameID == rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_nFrameUpdateID)
|
|
{
|
|
Texs.AddElem(tp);
|
|
}
|
|
}
|
|
|
|
if (Texs.Num())
|
|
{
|
|
qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallback);
|
|
}
|
|
|
|
Size = 0;
|
|
SizeDynAtl = 0;
|
|
SizeDynCom = 0;
|
|
PartSize = 0;
|
|
NonStrSize = 0;
|
|
for (i = 0; i < Texs.Num(); i++)
|
|
{
|
|
Size += Texs[i]->GetDataSize();
|
|
if (Texs[i]->GetFlags() & (FT_USAGE_DYNAMIC | FT_USAGE_RENDERTARGET))
|
|
{
|
|
if (Texs[i]->GetFlags() & FT_USAGE_ATLAS)
|
|
{
|
|
SizeDynAtl += Texs[i]->GetDataSize();
|
|
}
|
|
else
|
|
{
|
|
SizeDynCom += Texs[i]->GetDataSize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PartSize += Texs[i]->GetDeviceDataSize();
|
|
}
|
|
if (!Texs[i]->IsStreamed())
|
|
{
|
|
NonStrSize += Texs[i]->GetDataSize();
|
|
}
|
|
}
|
|
sprintf_s(buf, "Current tex. objects: %d (Size: %.3fMb, Dyn. Atlases: %.3f, Dyn. Separated: %.3f, Loaded: %.3f, NonStreamed: %.3f)", Texs.Num(), Size / (1024.0f * 1024.0f), SizeDynAtl / (1024.0f * 1024.0f), SizeDynCom / (1024.0f * 1024.0f), PartSize / (1024.0f * 1024.0f), NonStrSize / (1024.0f * 1024.0f));
|
|
rd->TextToScreenColor(4, 27, 1, 0, 0, 1, buf);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void CTexture::RT_LoadingUpdate()
|
|
{
|
|
CTexture::s_bStreamingFromHDD = gEnv->pSystem->GetStreamEngine()->IsStreamDataOnHDD();
|
|
CTexture::s_nStatsStreamPoolInUseMem = CTexture::s_pPoolMgr->GetInUseSize();
|
|
|
|
ITextureStreamer::EApplyScheduleFlags asf = CTexture::s_bPrecachePhase
|
|
? ITextureStreamer::eASF_InOut // Exclude the prep update, as it will be done by the RLT (and can be expensive)
|
|
: ITextureStreamer::eASF_Full;
|
|
|
|
s_pTextureStreamer->ApplySchedule(asf);
|
|
}
|
|
|
|
void CTexture::RLT_LoadingUpdate()
|
|
{
|
|
AZ_TRACE_METHOD();
|
|
s_pTextureStreamer->BeginUpdateSchedule();
|
|
}
|
|
|
|
Ang3 sDeltAngles(Ang3& Ang0, Ang3& Ang1)
|
|
{
|
|
Ang3 out;
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
float a0 = Ang0[i];
|
|
a0 = (float)((360.0 / 65536) * ((int)(a0 * (65536 / 360.0)) & 65535)); // angmod
|
|
float a1 = Ang1[i];
|
|
a1 = (float)((360.0 / 65536) * ((int)(a0 * (65536 / 360.0)) & 65535));
|
|
out[i] = a0 - a1;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
SEnvTexture* CTexture::FindSuitableEnvTex(Vec3& Pos, Ang3& Angs, bool bMustExist, [[maybe_unused]] int RendFlags, [[maybe_unused]] bool bUseExistingREs, [[maybe_unused]] CShader* pSH, [[maybe_unused]] CShaderResources* pRes, CRenderObject* pObj, bool bReflect, IRenderElement* pRE, bool* bMustUpdate)
|
|
{
|
|
SEnvTexture* cm = NULL;
|
|
float time0 = iTimer->GetAsyncCurTime();
|
|
|
|
int i;
|
|
float distO = 999999;
|
|
float adist = 999999;
|
|
int firstForUse = -1;
|
|
int firstFree = -1;
|
|
Vec3 objPos;
|
|
if (bMustUpdate)
|
|
{
|
|
*bMustUpdate = false;
|
|
}
|
|
if (!pObj)
|
|
{
|
|
bReflect = false;
|
|
}
|
|
else
|
|
{
|
|
if (bReflect)
|
|
{
|
|
Plane pl;
|
|
pRE->mfGetPlane(pl);
|
|
objPos = pl.MirrorPosition(Vec3(0, 0, 0));
|
|
}
|
|
else
|
|
if (pRE)
|
|
{
|
|
pRE->mfCenter(objPos, pObj);
|
|
}
|
|
else
|
|
{
|
|
objPos = pObj->GetTranslation();
|
|
}
|
|
}
|
|
float dist = 999999;
|
|
for (i = 0; i < MAX_ENVTEXTURES; i++)
|
|
{
|
|
SEnvTexture* cur = &CTexture::s_EnvTexts[i];
|
|
if (cur->m_bReflected != bReflect)
|
|
{
|
|
continue;
|
|
}
|
|
float s = (cur->m_CamPos - Pos).GetLengthSquared();
|
|
Ang3 angDelta = sDeltAngles(Angs, cur->m_Angle);
|
|
float a = angDelta.x * angDelta.x + angDelta.y * angDelta.y + angDelta.z * angDelta.z;
|
|
float so = 0;
|
|
if (bReflect)
|
|
{
|
|
so = (cur->m_ObjPos - objPos).GetLengthSquared();
|
|
}
|
|
if (s <= dist && a <= adist && so <= distO)
|
|
{
|
|
dist = s;
|
|
adist = a;
|
|
distO = so;
|
|
firstForUse = i;
|
|
if (!so && !s && !a)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (cur->m_pTex && !cur->m_pTex->m_pTexture && firstFree < 0)
|
|
{
|
|
firstFree = i;
|
|
}
|
|
}
|
|
if (bMustExist && firstForUse >= 0)
|
|
{
|
|
return &CTexture::s_EnvTexts[firstForUse];
|
|
}
|
|
if (bReflect)
|
|
{
|
|
dist = distO;
|
|
}
|
|
|
|
float curTime = iTimer->GetCurrTime();
|
|
int nUpdate = -2;
|
|
float fTimeInterval = dist * CRenderer::CV_r_envtexupdateinterval + CRenderer::CV_r_envtexupdateinterval * 0.5f;
|
|
float fDelta = curTime - CTexture::s_EnvTexts[firstForUse].m_TimeLastUpdated;
|
|
if (bMustExist)
|
|
{
|
|
nUpdate = -2;
|
|
}
|
|
else
|
|
if (dist > MAX_ENVTEXSCANDIST)
|
|
{
|
|
if (firstFree >= 0)
|
|
{
|
|
nUpdate = firstFree;
|
|
}
|
|
else
|
|
{
|
|
nUpdate = -1;
|
|
}
|
|
}
|
|
else
|
|
if (fDelta > fTimeInterval)
|
|
{
|
|
nUpdate = firstForUse;
|
|
}
|
|
if (nUpdate == -2)
|
|
{
|
|
// No need to update (Up to date)
|
|
return &CTexture::s_EnvTexts[firstForUse];
|
|
}
|
|
if (!CTexture::s_EnvTexts[nUpdate].m_pTex)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (nUpdate >= 0)
|
|
{
|
|
if (!CTexture::s_EnvTexts[nUpdate].m_pTex->m_pTexture || gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_fEnvTextUpdateTime < 0.1f)
|
|
{
|
|
int n = nUpdate;
|
|
CTexture::s_EnvTexts[n].m_TimeLastUpdated = curTime;
|
|
CTexture::s_EnvTexts[n].m_CamPos = Pos;
|
|
CTexture::s_EnvTexts[n].m_Angle = Angs;
|
|
CTexture::s_EnvTexts[n].m_ObjPos = objPos;
|
|
CTexture::s_EnvTexts[n].m_bReflected = bReflect;
|
|
if (bMustUpdate)
|
|
{
|
|
*bMustUpdate = true;
|
|
}
|
|
}
|
|
gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_fEnvTextUpdateTime += iTimer->GetAsyncCurTime() - time0;
|
|
return &CTexture::s_EnvTexts[nUpdate];
|
|
}
|
|
|
|
dist = 0;
|
|
firstForUse = -1;
|
|
for (i = 0; i < MAX_ENVTEXTURES; i++)
|
|
{
|
|
SEnvTexture* cur = &CTexture::s_EnvTexts[i];
|
|
if (dist < curTime - cur->m_TimeLastUpdated && !cur->m_bInprogress)
|
|
{
|
|
dist = curTime - cur->m_TimeLastUpdated;
|
|
firstForUse = i;
|
|
}
|
|
}
|
|
if (firstForUse < 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
int n = firstForUse;
|
|
CTexture::s_EnvTexts[n].m_TimeLastUpdated = curTime;
|
|
CTexture::s_EnvTexts[n].m_CamPos = Pos;
|
|
CTexture::s_EnvTexts[n].m_ObjPos = objPos;
|
|
CTexture::s_EnvTexts[n].m_Angle = Angs;
|
|
CTexture::s_EnvTexts[n].m_bReflected = bReflect;
|
|
if (bMustUpdate)
|
|
{
|
|
*bMustUpdate = true;
|
|
}
|
|
|
|
gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_fEnvTextUpdateTime += iTimer->GetAsyncCurTime() - time0;
|
|
return &CTexture::s_EnvTexts[n];
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CTexture::ShutDown()
|
|
{
|
|
uint32 i;
|
|
|
|
if (gRenDev->GetRenderType() == eRT_Null) // workaround to fix crash when quitting the dedicated server - because the textures are shared
|
|
{
|
|
return; // should be fixed soon
|
|
}
|
|
RT_FlushAllStreamingTasks(true);
|
|
|
|
ReleaseSystemTextures();
|
|
|
|
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_releaseallresourcesonexit)
|
|
{
|
|
SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
|
|
if (pRL)
|
|
{
|
|
int n = 0;
|
|
ResourcesMapItor itor;
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); )
|
|
{
|
|
CTexture* pTX = (CTexture*)itor->second;
|
|
itor++;
|
|
if (!pTX)
|
|
{
|
|
continue;
|
|
}
|
|
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_printmemoryleaks)
|
|
{
|
|
iLog->Log("Warning: CTexture::ShutDown: Texture %s was not deleted (%d)", pTX->GetName(), pTX->GetRefCounter());
|
|
}
|
|
SAFE_RELEASE_FORCE(pTX);
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s_ShaderTemplatesInitialized)
|
|
{
|
|
for (i = 0; i < EFTT_MAX; i++)
|
|
{
|
|
(*s_ShaderTemplates)[i].~CTexture();
|
|
}
|
|
}
|
|
s_ShaderTemplates->Free();
|
|
|
|
SAFE_DELETE(s_pTexNULL);
|
|
|
|
s_pPoolMgr->Flush();
|
|
}
|
|
|
|
bool CTexture::ReloadFile_Request(const char* szFileName)
|
|
{
|
|
s_xTexReloadLock.Lock();
|
|
s_vTexReloadRequests.insert(szFileName);
|
|
s_xTexReloadLock.Unlock();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CTexture::ReloadFile(const char* szFileName)
|
|
{
|
|
char realNameBuffer[256];
|
|
fpConvertDOSToUnixName(realNameBuffer, szFileName);
|
|
|
|
char* realName = realNameBuffer;
|
|
|
|
bool bStatus = false;
|
|
|
|
SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
|
|
if (pRL)
|
|
{
|
|
AUTO_LOCK(CBaseResource::s_cResLock);
|
|
AZStd::string normalizedFile;
|
|
AZStd::string fileExtension;
|
|
AzFramework::StringFunc::Path::GetExtension(szFileName, fileExtension);
|
|
if (szFileName[0] == '$' || fileExtension.empty())
|
|
{
|
|
//If the name starts with $ or it does not have any extension then it is one of the special texture that the engine requires and we would not be modifying the name
|
|
normalizedFile = szFileName;
|
|
}
|
|
else
|
|
{
|
|
char buffer[AZ_MAX_PATH_LEN];
|
|
IResourceCompilerHelper::GetOutputFilename(szFileName, buffer, sizeof(buffer)); // change texture filename extensions to dds
|
|
normalizedFile = buffer;
|
|
AZStd::to_lower(normalizedFile.begin(), normalizedFile.end());
|
|
PathUtil::ToUnixPath(normalizedFile.c_str());
|
|
}
|
|
|
|
CCryNameTSCRC Name = GenName(normalizedFile.c_str());
|
|
|
|
ResourcesMapItor itor = pRL->m_RMap.find(Name);
|
|
if (itor != pRL->m_RMap.end())
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
|
|
if (tp->Reload())
|
|
{
|
|
bStatus = true;
|
|
}
|
|
}
|
|
|
|
// Since we do not have the information whether the modified file was also reloaded with the FT_ALPHA flag we will try to reload that as well
|
|
Name = GenName(normalizedFile.c_str(), FT_ALPHA);
|
|
|
|
itor = pRL->m_RMap.find(Name);
|
|
if (itor != pRL->m_RMap.end())
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
|
|
if (tp->Reload())
|
|
{
|
|
bStatus = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
void CTexture::ReloadTextures()
|
|
{
|
|
SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
|
|
if (pRL)
|
|
{
|
|
ResourcesMapItor itor;
|
|
int nID = 0;
|
|
for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++, nID++)
|
|
{
|
|
CTexture* tp = (CTexture*)itor->second;
|
|
if (!tp)
|
|
{
|
|
continue;
|
|
}
|
|
if (!(tp->m_nFlags & FT_FROMIMAGE))
|
|
{
|
|
continue;
|
|
}
|
|
tp->Reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CTexture::SetNoTexture( const CTexture* pDefaultTexture /* = "NoTexture" entry */)
|
|
{
|
|
if (pDefaultTexture)
|
|
{
|
|
m_pDevTexture = pDefaultTexture->m_pDevTexture;
|
|
m_pDeviceShaderResource = pDefaultTexture->m_pDeviceShaderResource;
|
|
m_eTFSrc = pDefaultTexture->GetSrcFormat();
|
|
m_eTFDst = pDefaultTexture->GetDstFormat();
|
|
m_nMips = pDefaultTexture->GetNumMips();
|
|
m_nWidth = pDefaultTexture->GetWidth();
|
|
m_nHeight = pDefaultTexture->GetHeight();
|
|
m_nDepth = 1;
|
|
m_nDefState = pDefaultTexture->m_nDefState;
|
|
m_fAvgBrightness = 1.0f;
|
|
m_cMinColor = 0.0f;
|
|
m_cMaxColor = 1.0f;
|
|
m_cClearColor = ColorF(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
m_bNoTexture = true;
|
|
if (m_pFileTexMips)
|
|
{
|
|
Unlink();
|
|
StreamState_ReleaseInfo(this, m_pFileTexMips);
|
|
m_pFileTexMips = NULL;
|
|
}
|
|
m_bStreamed = false;
|
|
m_bPostponed = false;
|
|
m_nFlags |= FT_FAILED;
|
|
m_nActualSize = 0;
|
|
m_nPersistentSize = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
void CTexture::ReleaseSystemTextures()
|
|
{
|
|
if (s_pStatsTexWantedLists)
|
|
{
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
s_pStatsTexWantedLists[i].clear();
|
|
}
|
|
}
|
|
|
|
SAFE_RELEASE_FORCE(s_ptexRT_2D);
|
|
SAFE_RELEASE_FORCE(s_ptexCloudsLM);
|
|
|
|
SAFE_RELEASE_FORCE(s_ptexVolumetricFog);
|
|
SAFE_RELEASE_FORCE(s_ptexVolumetricFogDensityColor);
|
|
SAFE_RELEASE_FORCE(s_ptexVolumetricFogDensity);
|
|
SAFE_RELEASE_FORCE(s_ptexVolumetricClipVolumeStencil);
|
|
|
|
uint32 i;
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
SAFE_RELEASE_FORCE(s_ptexShadowID[i]);
|
|
}
|
|
|
|
SAFE_RELEASE_FORCE(s_ptexFromObj);
|
|
SAFE_RELEASE_FORCE(s_ptexSvoTree);
|
|
SAFE_RELEASE_FORCE(s_ptexSvoTris);
|
|
SAFE_RELEASE_FORCE(s_ptexSvoGlobalCM);
|
|
SAFE_RELEASE_FORCE(s_ptexSvoRgbs);
|
|
SAFE_RELEASE_FORCE(s_ptexSvoNorm);
|
|
SAFE_RELEASE_FORCE(s_ptexSvoOpac);
|
|
SAFE_RELEASE_FORCE(s_ptexFromObjCM);
|
|
|
|
SAFE_RELEASE_FORCE(s_ptexVolObj_Density);
|
|
SAFE_RELEASE_FORCE(s_ptexVolObj_Shadow);
|
|
|
|
SAFE_RELEASE_FORCE(s_ptexColorChart);
|
|
|
|
for (i = 0; i < MAX_ENVCUBEMAPS; i++)
|
|
{
|
|
s_EnvCMaps[i].Release();
|
|
}
|
|
for (i = 0; i < MAX_ENVTEXTURES; i++)
|
|
{
|
|
s_EnvTexts[i].Release();
|
|
}
|
|
|
|
SAFE_RELEASE_FORCE(s_ptexMipColors_Diffuse);
|
|
SAFE_RELEASE_FORCE(s_ptexMipColors_Bump);
|
|
SAFE_RELEASE_FORCE(s_ptexSkyDomeMie);
|
|
SAFE_RELEASE_FORCE(s_ptexSkyDomeRayleigh);
|
|
SAFE_RELEASE_FORCE(s_ptexSkyDomeMoon);
|
|
SAFE_RELEASE_FORCE(s_ptexRT_ShadowPool);
|
|
SAFE_RELEASE_FORCE(s_ptexRT_ShadowStub);
|
|
|
|
SAFE_RELEASE_FORCE(s_ptexSceneNormalsMapMS);
|
|
SAFE_RELEASE_FORCE(s_ptexSceneDiffuseAccMapMS);
|
|
SAFE_RELEASE_FORCE(s_ptexSceneSpecularAccMapMS);
|
|
|
|
SAFE_RELEASE_FORCE(s_defaultEnvironmentProbeDummy);
|
|
|
|
s_CustomRT_2D->Free();
|
|
|
|
s_pPoolMgr->Flush();
|
|
|
|
// release targets pools
|
|
SDynTexture::ShutDown();
|
|
SDynTexture2::ShutDown();
|
|
|
|
ReleaseMiscTargets();
|
|
|
|
m_bLoadedSystem = false;
|
|
}
|
|
|
|
void CTexture::LoadDefaultSystemTextures()
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION;
|
|
#if !defined(NULL_RENDERER)
|
|
char str[256];
|
|
int i;
|
|
|
|
if (!m_bLoadedSystem)
|
|
{
|
|
|
|
|
|
m_bLoadedSystem = true;
|
|
|
|
// Default Template textures
|
|
int nRTFlags = FT_DONT_RELEASE | FT_DONT_STREAM | FT_STATE_CLAMP | FT_USAGE_RENDERTARGET;
|
|
s_ptexMipColors_Diffuse = CTexture::CreateTextureObject("$MipColors_Diffuse", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_MIPCOLORS_DIFFUSE);
|
|
s_ptexMipColors_Bump = CTexture::CreateTextureObject("$MipColors_Bump", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_MIPCOLORS_BUMP);
|
|
|
|
s_ptexRT_2D = CTexture::CreateTextureObject("$RT_2D", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_RT_2D);
|
|
|
|
s_ptexRainOcclusion = CTexture::CreateTextureObject("$RainOcclusion", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
s_ptexRainSSOcclusion[0] = CTexture::CreateTextureObject("$RainSSOcclusion0", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
s_ptexRainSSOcclusion[1] = CTexture::CreateTextureObject("$RainSSOcclusion1", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
|
|
s_ptexFromObj = CTexture::CreateTextureObject("FromObj", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_FROMOBJ);
|
|
s_ptexSvoTree = CTexture::CreateTextureObject("SvoTree", 0, 0, 1, eTT_3D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SVOTREE);
|
|
s_ptexSvoTris = CTexture::CreateTextureObject("SvoTris", 0, 0, 1, eTT_3D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SVOTRIS);
|
|
s_ptexSvoGlobalCM = CTexture::CreateTextureObject("SvoGlobalCM", 0, 0, 1, eTT_Cube, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SVOGLCM);
|
|
s_ptexSvoRgbs = CTexture::CreateTextureObject("SvoRgbs", 0, 0, 1, eTT_3D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SVORGBS);
|
|
s_ptexSvoNorm = CTexture::CreateTextureObject("SvoNorm", 0, 0, 1, eTT_3D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SVONORM);
|
|
s_ptexSvoOpac = CTexture::CreateTextureObject("SvoOpac", 0, 0, 1, eTT_3D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SVOOPAC);
|
|
s_ptexFromObjCM = CTexture::CreateTextureObject("$FromObjCM", 0, 0, 1, eTT_Cube, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_FROMOBJ_CM);
|
|
|
|
s_ptexZTargetDownSample[0] = CTexture::CreateTextureObject("$ZTargetDownSample0", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM, eTF_Unknown);
|
|
s_ptexZTargetDownSample[1] = CTexture::CreateTextureObject("$ZTargetDownSample1", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM, eTF_Unknown);
|
|
s_ptexZTargetDownSample[2] = CTexture::CreateTextureObject("$ZTargetDownSample2", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM, eTF_Unknown);
|
|
s_ptexZTargetDownSample[3] = CTexture::CreateTextureObject("$ZTargetDownSample3", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM, eTF_Unknown);
|
|
|
|
s_ptexSceneNormalsMapMS = CTexture::CreateTextureObject("$SceneNormalsMapMS", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SCENE_NORMALMAP_MS);
|
|
s_ptexSceneDiffuseAccMapMS = CTexture::CreateTextureObject("$SceneDiffuseAccMS", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SCENE_DIFFUSE_ACC_MS);
|
|
s_ptexSceneSpecularAccMapMS = CTexture::CreateTextureObject("$SceneSpecularAccMS", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SCENE_SPECULAR_ACC_MS);
|
|
|
|
s_ptexSceneNormalsMapMS = CTexture::CreateTextureObject("$SceneNormalsMapMS", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SCENE_NORMALMAP_MS);
|
|
s_ptexSceneDiffuseAccMapMS = CTexture::CreateTextureObject("$SceneDiffuseAccMS", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SCENE_DIFFUSE_ACC_MS);
|
|
s_ptexSceneSpecularAccMapMS = CTexture::CreateTextureObject("$SceneSpecularAccMS", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SCENE_SPECULAR_ACC_MS);
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION TEXTURE_CPP_SECTION_4
|
|
#include AZ_RESTRICTED_FILE(Texture_cpp)
|
|
#endif
|
|
s_ptexRT_ShadowPool = CTexture::CreateTextureObject("$RT_ShadowPool", 0, 0, 1, eTT_2D, FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_USAGE_DEPTHSTENCIL, eTF_Unknown);
|
|
s_ptexRT_ShadowStub = CTexture::CreateTextureObject("$RT_ShadowStub", 0, 0, 1, eTT_2D, FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_USAGE_DEPTHSTENCIL, eTF_Unknown);
|
|
|
|
s_ptexDepthBufferQuarter = CTexture::CreateTextureObject("$DepthBufferQuarter", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_USAGE_DEPTHSTENCIL, eTF_Unknown);
|
|
|
|
if (!s_ptexModelHudBuffer)
|
|
{
|
|
s_ptexModelHudBuffer = CTexture::CreateTextureObject("$ModelHud", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_MODELHUD);
|
|
}
|
|
|
|
if (!s_ptexBackBuffer)
|
|
{
|
|
s_ptexSceneTarget = CTexture::CreateTextureObject("$SceneTarget", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SCENE_TARGET);
|
|
s_ptexCurrSceneTarget = s_ptexSceneTarget;
|
|
|
|
s_ptexSceneTargetR11G11B10F[0] = CTexture::CreateTextureObject("$SceneTargetR11G11B10F_0", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexSceneTargetR11G11B10F[1] = CTexture::CreateTextureObject("$SceneTargetR11G11B10F_1", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexSceneTargetScaledR11G11B10F[0] = CTexture::CreateTextureObject("$SceneTargetScaled0R11G11B10F", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexSceneTargetScaledR11G11B10F[1] = CTexture::CreateTextureObject("$SceneTargetScaled1R11G11B10F", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexSceneTargetScaledR11G11B10F[2] = CTexture::CreateTextureObject("$SceneTargetScaled2R11G11B10F", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexSceneTargetScaledR11G11B10F[3] = CTexture::CreateTextureObject("$SceneTargetScaled3R11G11B10F", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
|
|
s_ptexVelocity = CTexture::CreateTextureObject("$Velocity", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexVelocityTiles[0] = CTexture::CreateTextureObject("$VelocityTilesTmp0", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexVelocityTiles[1] = CTexture::CreateTextureObject("$VelocityTilesTmp1", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexVelocityTiles[2] = CTexture::CreateTextureObject("$VelocityTiles", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexVelocityObjects[0] = CTexture::CreateTextureObject("$VelocityObjects", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
if (gRenDev->m_bDualStereoSupport)
|
|
{
|
|
s_ptexVelocityObjects[1] = CTexture::CreateTextureObject("$VelocityObjects_R", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
}
|
|
|
|
#if defined(OPENGL_ES) || defined(CRY_USE_METAL)
|
|
if (gcpRendD3D && gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
|
|
{
|
|
s_ptexGmemStenLinDepth = CTexture::CreateTextureObject("$GmemStenLinDepth", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
}
|
|
#endif
|
|
|
|
s_ptexBackBuffer = CTexture::CreateTextureObject("$BackBuffer", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_BACKBUFFERMAP);
|
|
|
|
s_ptexPrevFrameScaled = CTexture::CreateTextureObject("$PrevFrameScale", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
s_ptexWaterRipplesDDN = CTexture::CreateTextureObject("$WaterRipplesDDN_0", 256, 256, 1, eTT_2D, /*FT_DONT_RELEASE |*/ FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_FORCE_MIPS, eTF_Unknown, TO_WATERRIPPLESMAP);
|
|
|
|
s_ptexBackBufferScaled[0] = CTexture::CreateTextureObject("$BackBufferScaled_d2", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_BACKBUFFERSCALED_D2);
|
|
s_ptexBackBufferScaled[1] = CTexture::CreateTextureObject("$BackBufferScaled_d4", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_BACKBUFFERSCALED_D4);
|
|
s_ptexBackBufferScaled[2] = CTexture::CreateTextureObject("$BackBufferScaled_d8", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_BACKBUFFERSCALED_D8);
|
|
|
|
s_ptexBackBufferScaledTemp[0] = CTexture::CreateTextureObject("$BackBufferScaledTemp_d2", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
s_ptexBackBufferScaledTemp[1] = CTexture::CreateTextureObject("$BackBufferScaledTemp_d4", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, -1);
|
|
|
|
s_ptexSceneNormalsMap = CTexture::CreateTextureObject("$SceneNormalsMap", 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8, TO_SCENE_NORMALMAP);
|
|
s_ptexSceneNormalsBent = CTexture::CreateTextureObject("$SceneNormalsBent", 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8);
|
|
s_ptexSceneDiffuse = CTexture::CreateTextureObject("$SceneDiffuse", 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8);
|
|
ETEX_Format rtTextureFormat = eTF_R8G8B8A8;
|
|
|
|
// Slimming GBuffer requires only one channel for specular due to packing of RGB values into YPbPr and
|
|
// specular components into less channels, thus saving bandwidth by not including G,B,A channels (75% saving)
|
|
if(CRenderer::CV_r_SlimGBuffer == 1)
|
|
{
|
|
rtTextureFormat = eTF_R8;
|
|
}
|
|
s_ptexSceneSpecular = CTexture::CreateTextureObject("$SceneSpecular", 0, 0, 1, eTT_2D, nRTFlags, rtTextureFormat);
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION TEXTURE_CPP_SECTION_5
|
|
#include AZ_RESTRICTED_FILE(Texture_cpp)
|
|
#endif
|
|
|
|
#if defined(AZ_PLATFORM_IOS)
|
|
int nRTSceneDiffuseFlags = nRTFlags;
|
|
static ICVar* pVar = gEnv->pConsole->GetCVar("e_ShadowsClearShowMaskAtLoad");
|
|
if (pVar && !pVar->GetIVal())
|
|
{
|
|
nRTSceneDiffuseFlags |= FT_USAGE_MEMORYLESS;
|
|
}
|
|
s_ptexSceneDiffuseAccMap = CTexture::CreateTextureObject("$SceneDiffuseAcc", 0, 0, 1, eTT_2D, nRTSceneDiffuseFlags, eTF_R8G8B8A8, TO_SCENE_DIFFUSE_ACC);
|
|
#else
|
|
s_ptexSceneDiffuseAccMap = CTexture::CreateTextureObject("$SceneDiffuseAcc", 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8, TO_SCENE_DIFFUSE_ACC);
|
|
#endif
|
|
s_ptexSceneSpecularAccMap = CTexture::CreateTextureObject("$SceneSpecularAcc", 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8, TO_SCENE_SPECULAR_ACC);
|
|
s_ptexAmbientLookup = CTexture::CreateTextureObject("$AmbientLookup", 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8);
|
|
s_ptexShadowMask = CTexture::CreateTextureObject("$ShadowMask", 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8, TO_SHADOWMASK);
|
|
|
|
s_ptexFlaresGather = CTexture::CreateTextureObject("$FlaresGather", 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8);
|
|
for (i = 0; i < MAX_OCCLUSION_READBACK_TEXTURES; i++)
|
|
{
|
|
azsprintf(str, "$FlaresOcclusion_%d", i);
|
|
s_ptexFlaresOcclusionRing[i] = CTexture::CreateTextureObject(str, 0, 0, 1, eTT_2D, nRTFlags, eTF_R8G8B8A8);
|
|
}
|
|
|
|
// fixme: get texture resolution from CREWaterOcean
|
|
uint32 waterOceanMapFlags = FT_DONT_RELEASE | FT_NOMIPS | FT_USAGE_DYNAMIC | FT_DONT_STREAM;
|
|
uint32 waterVolumeTempFlags = FT_NOMIPS | FT_USAGE_DYNAMIC | FT_DONT_STREAM;
|
|
#if CRY_USE_METAL
|
|
//We are now using the GPU to copy data into this texture. As a result we need to tag this texture as MtlTextureUsageRenderTarget so that on Metal can set the appropriate Usage flag.
|
|
waterOceanMapFlags |= FT_USAGE_RENDERTARGET;
|
|
waterVolumeTempFlags |= FT_USAGE_RENDERTARGET;
|
|
#endif
|
|
s_ptexWaterOcean = CTexture::CreateTextureObject("$WaterOceanMap", 64, 64, 1, eTT_2D, waterOceanMapFlags, eTF_Unknown, TO_WATEROCEANMAP);
|
|
s_ptexWaterVolumeTemp = CTexture::CreateTextureObject("$WaterVolumeTemp", 64, 64, 1, eTT_2D, waterVolumeTempFlags, eTF_Unknown);
|
|
|
|
s_ptexWaterVolumeDDN = CTexture::CreateTextureObject("$WaterVolumeDDN", 64, 64, 1, eTT_2D, /*FT_DONT_RELEASE |*/ FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_FORCE_MIPS, eTF_Unknown, TO_WATERVOLUMEMAP);
|
|
s_ptexWaterVolumeRefl[0] = CTexture::CreateTextureObject("$WaterVolumeRefl", 64, 64, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_FORCE_MIPS, eTF_Unknown, TO_WATERVOLUMEREFLMAP);
|
|
s_ptexWaterVolumeRefl[1] = CTexture::CreateTextureObject("$WaterVolumeReflPrev", 64, 64, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_FORCE_MIPS, eTF_Unknown, TO_WATERVOLUMEREFLMAPPREV);
|
|
s_ptexWaterCaustics[0] = CTexture::CreateTextureObject("$WaterVolumeCaustics", 512, 512, 1, eTT_2D, /*FT_DONT_RELEASE |*/ FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_WATERVOLUMECAUSTICSMAP);
|
|
s_ptexWaterCaustics[1] = CTexture::CreateTextureObject("$WaterVolumeCausticsTemp", 512, 512, 1, eTT_2D, /*FT_DONT_RELEASE |*/ FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_WATERVOLUMECAUSTICSMAPTEMP);
|
|
|
|
s_ptexRainDropsRT[0] = CTexture::CreateTextureObject("$RainDropsAccumRT_0", 512, 512, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
s_ptexRainDropsRT[1] = CTexture::CreateTextureObject("$RainDropsAccumRT_1", 512, 512, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
|
|
if (!s_ptexZTarget)
|
|
{
|
|
//for d3d10 we cannot free it during level transition, therefore allocate once and keep it
|
|
#if defined(OPENGL_ES) || defined(CRY_USE_METAL)
|
|
// Custom Z-Target for GMEM render path
|
|
if (gcpRendD3D && gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
|
|
{
|
|
s_ptexZTarget = CTexture::s_ptexGmemStenLinDepth;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
s_ptexZTarget = CTexture::CreateTextureObject("$ZTarget", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
}
|
|
}
|
|
|
|
s_ptexFurZTarget = CTexture::CreateTextureObject("$FurZTarget", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
|
|
s_ptexZTargetScaled = CTexture::CreateTextureObject("$ZTargetScaled", 0, 0, 1, eTT_2D,
|
|
FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_DOWNSCALED_ZTARGET_FOR_AO);
|
|
|
|
s_ptexZTargetScaled2 = CTexture::CreateTextureObject("$ZTargetScaled2", 0, 0, 1, eTT_2D,
|
|
FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_QUARTER_ZTARGET_FOR_AO);
|
|
}
|
|
|
|
#if defined(OPENGL_ES) || defined(CRY_USE_METAL)
|
|
// GMEM render path uses CTexture::s_ptexSceneSpecularAccMap as the HDR Target
|
|
// It gets set in CDeferredShading::CreateDeferredMaps()
|
|
if (gcpRendD3D && !gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
|
|
{
|
|
s_ptexHDRTarget = CTexture::CreateTextureObject("$HDRTarget", 0, 0, 1, eTT_2D, nRTFlags, eTF_Unknown);
|
|
}
|
|
#elif defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION TEXTURE_CPP_SECTION_6
|
|
#include AZ_RESTRICTED_FILE(Texture_cpp)
|
|
#endif
|
|
|
|
// Create dummy texture object for terrain and clouds lightmap
|
|
s_ptexCloudsLM = CTexture::CreateTextureObject("$CloudsLM", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_CLOUDS_LM);
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
azsprintf(str, "$FromRE_%d", i);
|
|
if (!s_ptexFromRE[i])
|
|
{
|
|
s_ptexFromRE[i] = CTexture::CreateTextureObject(str, 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_FROMRE0 + i);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
azsprintf(str, "$ShadowID_%d", i);
|
|
s_ptexShadowID[i] = CTexture::CreateTextureObject(str, 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SHADOWID0 + i);
|
|
}
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
azsprintf(str, "$FromRE%d_FromContainer", i);
|
|
if (!s_ptexFromRE_FromContainer[i])
|
|
{
|
|
s_ptexFromRE_FromContainer[i] = CTexture::CreateTextureObject(str, 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_FROMRE0_FROM_CONTAINER + i);
|
|
}
|
|
}
|
|
|
|
s_ptexVolObj_Density = CTexture::CreateTextureObject("$VolObj_Density", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_VOLOBJ_DENSITY);
|
|
s_ptexVolObj_Shadow = CTexture::CreateTextureObject("$VolObj_Shadow", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_VOLOBJ_SHADOW);
|
|
|
|
s_ptexColorChart = CTexture::CreateTextureObject("$ColorChart", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_COLORCHART);
|
|
|
|
s_ptexSkyDomeMie = CTexture::CreateTextureObject("$SkyDomeMie", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SKYDOME_MIE);
|
|
s_ptexSkyDomeRayleigh = CTexture::CreateTextureObject("$SkyDomeRayleigh", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SKYDOME_RAYLEIGH);
|
|
s_ptexSkyDomeMoon = CTexture::CreateTextureObject("$SkyDomeMoon", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET, eTF_Unknown, TO_SKYDOME_MOON);
|
|
|
|
for (i = 0; i < EFTT_MAX; i++)
|
|
{
|
|
::new(&((*s_ShaderTemplates)[i]))CTexture(FT_DONT_RELEASE);
|
|
(*s_ShaderTemplates)[i].SetCustomID(EFTT_DIFFUSE + i);
|
|
(*s_ShaderTemplates)[i].SetFlags(FT_DONT_RELEASE);
|
|
}
|
|
s_ShaderTemplatesInitialized = true;
|
|
|
|
s_pTexNULL = new CTexture(FT_DONT_RELEASE);
|
|
|
|
s_ptexVolumetricFog = CTexture::CreateTextureObject("$VolumetricInscattering", 0, 0, 0, eTT_3D, FT_NOMIPS | FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_UNORDERED_ACCESS, eTF_Unknown);
|
|
s_ptexVolumetricFogDensityColor = CTexture::CreateTextureObject("$DensityColorVolume", 0, 0, 0, eTT_3D, FT_NOMIPS | FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_USAGE_UNORDERED_ACCESS, eTF_Unknown);
|
|
s_ptexVolumetricFogDensity = CTexture::CreateTextureObject("$DensityVolume", 0, 0, 0, eTT_3D, FT_NOMIPS | FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_RENDERTARGET | FT_USAGE_UNORDERED_ACCESS, eTF_Unknown);
|
|
s_ptexVolumetricClipVolumeStencil = CTexture::CreateTextureObject("$ClipVolumeStencilVolume", 0, 0, 0, eTT_2D, FT_NOMIPS | FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_DEPTHSTENCIL | FT_USAGE_RENDERTARGET, eTF_Unknown);
|
|
|
|
// Create dummy texture object the "default environment probe". This is only used for forward rendered passes that do not currently support tiled lighting.
|
|
// This texture object is solely used for the association between the string "$DefaultEnvironmentProbe" and the enum TO_DEFAULT_ENVIRONMENT_PROBE
|
|
if (!s_defaultEnvironmentProbeDummy)
|
|
{
|
|
s_defaultEnvironmentProbeDummy = CTexture::CreateTextureObject("$DefaultEnvironmentProbe", 0, 0, 1, eTT_2D, FT_DONT_RELEASE | FT_DONT_STREAM, eTF_Unknown, TO_DEFAULT_ENVIRONMENT_PROBE);
|
|
}
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION TEXTURE_CPP_SECTION_7
|
|
#include AZ_RESTRICTED_FILE(Texture_cpp)
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const char* CTexture::GetFormatName() const
|
|
{
|
|
return NameForTextureFormat(GetDstFormat());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const char* CTexture::GetTypeName() const
|
|
{
|
|
return NameForTextureType(GetTextureType());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CRenderer::EF_AddRTStat(CTexture* pTex, int nFlags, int nW, int nH)
|
|
{
|
|
SRTargetStat TS;
|
|
int nSize;
|
|
ETEX_Format eTF;
|
|
if (!pTex)
|
|
{
|
|
eTF = eTF_R8G8B8A8;
|
|
if (nW < 0)
|
|
{
|
|
nW = m_width;
|
|
}
|
|
if (nH < 0)
|
|
{
|
|
nH = m_height;
|
|
}
|
|
nSize = CTexture::TextureDataSize(nW, nH, 1, 1, 1, eTF);
|
|
TS.m_Name = "Back buffer";
|
|
}
|
|
else
|
|
{
|
|
eTF = pTex->GetDstFormat();
|
|
if (nW < 0)
|
|
{
|
|
nW = pTex->GetWidth();
|
|
}
|
|
if (nH < 0)
|
|
{
|
|
nH = pTex->GetHeight();
|
|
}
|
|
nSize = CTexture::TextureDataSize(nW, nH, 1, pTex->GetNumMips(), 1, eTF);
|
|
const char* szName = pTex->GetName();
|
|
if (szName && szName[0] == '$')
|
|
{
|
|
TS.m_Name = string("@") + string(&szName[1]);
|
|
}
|
|
else
|
|
{
|
|
TS.m_Name = szName;
|
|
}
|
|
}
|
|
TS.m_eTF = eTF;
|
|
|
|
if (nFlags > 0)
|
|
{
|
|
if (nFlags == 1)
|
|
{
|
|
TS.m_Name += " (Target)";
|
|
}
|
|
else
|
|
if (nFlags == 2)
|
|
{
|
|
TS.m_Name += " (Depth)";
|
|
nSize = nW * nH * 3;
|
|
}
|
|
else
|
|
if (nFlags == 4)
|
|
{
|
|
TS.m_Name += " (Stencil)";
|
|
nSize = nW * nH;
|
|
}
|
|
else
|
|
if (nFlags == 3)
|
|
{
|
|
TS.m_Name += " (Target + Depth)";
|
|
nSize += nW * nH * 3;
|
|
}
|
|
else
|
|
if (nFlags == 6)
|
|
{
|
|
TS.m_Name += " (Depth + Stencil)";
|
|
nSize = nW * nH * 4;
|
|
}
|
|
else
|
|
if (nFlags == 5)
|
|
{
|
|
TS.m_Name += " (Target + Stencil)";
|
|
nSize += nW * nH;
|
|
}
|
|
else
|
|
if (nFlags == 7)
|
|
{
|
|
TS.m_Name += " (Target + Depth + Stencil)";
|
|
nSize += nW * nH * 4;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
TS.m_nSize = nSize;
|
|
TS.m_nWidth = nW;
|
|
TS.m_nHeight = nH;
|
|
|
|
m_RP.m_RTStats.push_back(TS);
|
|
}
|
|
|
|
void CRenderer::EF_PrintRTStats(const char* szName)
|
|
{
|
|
const int nYstep = 14;
|
|
int nY = 30; // initial Y pos
|
|
int nX = 20; // initial X pos
|
|
ColorF col = Col_Green;
|
|
Draw2dLabel((float)nX, (float)nY, 1.6f, &col.r, false, szName);
|
|
nX += 10;
|
|
nY += 25;
|
|
|
|
col = Col_White;
|
|
int nYstart = nY;
|
|
int nSize = 0;
|
|
for (int i = 0; i < m_RP.m_RTStats.size(); i++)
|
|
{
|
|
SRTargetStat* pRT = &m_RP.m_RTStats[i];
|
|
|
|
Draw2dLabel((float)nX, (float)nY, 1.4f, &col.r, false, "%s (%d x %d x %s), Size: %.3f Mb", pRT->m_Name.c_str(), pRT->m_nWidth, pRT->m_nHeight, CTexture::NameForTextureFormat(pRT->m_eTF), (float)pRT->m_nSize / 1024.0f / 1024.0f);
|
|
nY += nYstep;
|
|
if (nY >= m_height - 25)
|
|
{
|
|
nY = nYstart;
|
|
nX += 500;
|
|
}
|
|
nSize += pRT->m_nSize;
|
|
}
|
|
col = Col_Yellow;
|
|
Draw2dLabel((float)nX, (float)(nY + 10), 1.4f, &col.r, false, "Total: %d RT's, Size: %.3f Mb", m_RP.m_RTStats.size(), nSize / 1024.0f / 1024.0f);
|
|
}
|
|
|
|
bool CTexture::IsMSAAChanged()
|
|
{
|
|
const RenderTargetData* pRtdt = m_pRenderTargetData;
|
|
#if defined(NULL_RENDERER)
|
|
return false;
|
|
#else
|
|
return pRtdt && (pRtdt->m_nMSAASamples != gRenDev->m_RP.m_MSAAData.Type || pRtdt->m_nMSAAQuality != gRenDev->m_RP.m_MSAAData.Quality);
|
|
#endif
|
|
}
|
|
|
|
STexPool::~STexPool()
|
|
{
|
|
STexPoolItemHdr* pITH = m_ItemsList.m_Next;
|
|
|
|
while (pITH != &m_ItemsList)
|
|
{
|
|
STexPoolItemHdr* pNext = pITH->m_Next;
|
|
STexPoolItem* pIT = static_cast<STexPoolItem*>(pITH);
|
|
CryLogAlways("***** Texture %p (%s) still in pool %p! Memory leak and crash will follow *****\n", pIT->m_pTex, pIT->m_pTex ? pIT->m_pTex->GetName() : "NULL", this);
|
|
|
|
if (pIT->m_pTex)
|
|
{
|
|
pIT->m_pTex->ReleaseDeviceTexture(true); // Try to recover in release
|
|
}
|
|
|
|
*const_cast<STexPool**>(&pIT->m_pOwner) = NULL;
|
|
pITH = pNext;
|
|
}
|
|
}
|
|
|
|
const ETEX_Type CTexture::GetTextureType() const
|
|
{
|
|
return m_eTT;
|
|
}
|
|
|
|
void CTexture::SetTextureType(ETEX_Type type)
|
|
{
|
|
// Only set the type if we have not loaded the file and created the device
|
|
// texture
|
|
if (!m_pDevTexture)
|
|
{
|
|
m_eTT = type;
|
|
}
|
|
}
|
|
|
|
const int CTexture::GetTextureID() const
|
|
{
|
|
return GetID();
|
|
}
|
|
|
|
#ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
|
|
|
|
const ColorB* CTexture::GetLowResSystemCopy(uint16& nWidth, uint16& nHeight, int** ppLowResSystemCopyAtlasId)
|
|
{
|
|
const LowResSystemCopyType::iterator& it = s_LowResSystemCopy.find(this);
|
|
if (it != CTexture::s_LowResSystemCopy.end())
|
|
{
|
|
nWidth = (*it).second.m_nLowResCopyWidth;
|
|
nHeight = (*it).second.m_nLowResCopyHeight;
|
|
*ppLowResSystemCopyAtlasId = &(*it).second.m_nLowResSystemCopyAtlasId;
|
|
return (*it).second.m_lowResSystemCopy.GetElements();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CTexture::PrepareLowResSystemCopy(const byte* pTexData, bool bTexDataHasAllMips)
|
|
{
|
|
if (m_eTT != eTT_2D || (m_nMips <= 1 && (m_nWidth > 16 || m_nHeight > 16)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// this function handles only compressed textures for now
|
|
if (m_eTFDst != eTF_BC3 && m_eTFDst != eTF_BC1 && m_eTFDst != eTF_BC2)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// make sure we skip non diffuse textures
|
|
if (strstr(GetName(), "_ddn")
|
|
|| strstr(GetName(), "_ddna")
|
|
|| strstr(GetName(), "_mask")
|
|
|| strstr(GetName(), "_spec.")
|
|
|| strstr(GetName(), "_gloss")
|
|
|| strstr(GetName(), "_displ")
|
|
|| strstr(GetName(), "characters")
|
|
|| strstr(GetName(), "$")
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pTexData)
|
|
{
|
|
SLowResSystemCopy& rSysCopy = s_LowResSystemCopy[this];
|
|
|
|
rSysCopy.m_nLowResCopyWidth = m_nWidth;
|
|
rSysCopy.m_nLowResCopyHeight = m_nHeight;
|
|
|
|
int nSrcOffset = 0;
|
|
int nMipId = 0;
|
|
|
|
while ((rSysCopy.m_nLowResCopyWidth > 16 || rSysCopy.m_nLowResCopyHeight > 16 || nMipId < 2) && (rSysCopy.m_nLowResCopyWidth >= 8 && rSysCopy.m_nLowResCopyHeight >= 8))
|
|
{
|
|
nSrcOffset += TextureDataSize(rSysCopy.m_nLowResCopyWidth, rSysCopy.m_nLowResCopyHeight, 1, 1, 1, m_eTFDst);
|
|
rSysCopy.m_nLowResCopyWidth /= 2;
|
|
rSysCopy.m_nLowResCopyHeight /= 2;
|
|
nMipId++;
|
|
}
|
|
|
|
int nSizeDxtMip = TextureDataSize(rSysCopy.m_nLowResCopyWidth, rSysCopy.m_nLowResCopyHeight, 1, 1, 1, m_eTFDst);
|
|
int nSizeRgbaMip = TextureDataSize(rSysCopy.m_nLowResCopyWidth, rSysCopy.m_nLowResCopyHeight, 1, 1, 1, eTF_R8G8B8A8);
|
|
|
|
rSysCopy.m_lowResSystemCopy.CheckAllocated(nSizeRgbaMip / sizeof(ColorB));
|
|
|
|
gRenDev->DXTDecompress(pTexData + (bTexDataHasAllMips ? nSrcOffset : 0), nSizeDxtMip,
|
|
(byte*)rSysCopy.m_lowResSystemCopy.GetElements(), rSysCopy.m_nLowResCopyWidth, rSysCopy.m_nLowResCopyHeight, 1, m_eTFDst, false, 4);
|
|
}
|
|
}
|
|
|
|
#endif // TEXTURE_GET_SYSTEM_COPY_SUPPORT
|
|
|
|
void CTexture::InvalidateDeviceResource(uint32 dirtyFlags)
|
|
{
|
|
//In the editor, multiple worker threads could destroy device resource sets
|
|
//which point to this texture. We need to lock to avoid a race-condition.
|
|
AZStd::lock_guard<AZStd::mutex> lockGuard(*m_invalidateCallbacksMutex);
|
|
|
|
for (const auto& cb : m_invalidateCallbacks)
|
|
{
|
|
cb.second(dirtyFlags);
|
|
}
|
|
}
|
|
|
|
void CTexture::AddInvalidateCallback(void* listener, InvalidateCallbackType callback)
|
|
{
|
|
//In the editor, multiple worker threads could destroy device resource sets
|
|
//which point to this texture. We need to lock to avoid a race-condition.
|
|
AZStd::lock_guard<AZStd::mutex> lockGuard(*m_invalidateCallbacksMutex);
|
|
|
|
m_invalidateCallbacks.insert(AZStd::pair<void*, InvalidateCallbackType>(listener, callback));
|
|
}
|
|
|
|
void CTexture::RemoveInvalidateCallbacks(void* listener)
|
|
{
|
|
//In the editor, multiple worker threads could destroy device resource sets
|
|
//which point to this texture. We need to lock to avoid a race-condition.
|
|
AZStd::lock_guard<AZStd::mutex> lockGuard(*m_invalidateCallbacksMutex);
|
|
|
|
m_invalidateCallbacks.erase(listener);
|
|
}
|
|
|
|
void CTexture::ApplyDepthTextureState(int unit, int nFilter, bool clamp)
|
|
{
|
|
if (s_ptexZTarget != nullptr)
|
|
{
|
|
STexState depthTextState(nFilter, clamp);
|
|
s_ptexZTarget->Apply(unit, GetTexState(depthTextState));
|
|
}
|
|
}
|
|
|
|
CTexture* CTexture::GetZTargetTexture()
|
|
{
|
|
return s_ptexZTarget;
|
|
}
|
|
|
|
int CTexture::GetTextureState(const STexState& TS)
|
|
{
|
|
return GetTexState(TS);
|
|
}
|
|
|
|
void CTexture::ApplyForID(int id, int nTUnit, int nTState, int nTexMaterialSlot, int nSUnit, bool useWhiteDefault)
|
|
{
|
|
CTexture* pTex = id > 0 ? CTexture::GetByID(id) : nullptr;
|
|
if (pTex)
|
|
{
|
|
pTex->Apply(nTUnit, nTState, nTexMaterialSlot, nSUnit);
|
|
}
|
|
else if (useWhiteDefault)
|
|
{
|
|
CTextureManager::Instance()->GetWhiteTexture()->Apply(nTUnit, nTState, nTexMaterialSlot, nSUnit);
|
|
}
|
|
}
|
|
|
|
CTexAnim::CTexAnim()
|
|
{
|
|
m_nRefCount = 1;
|
|
m_Rand = 0;
|
|
m_NumAnimTexs = 0;
|
|
m_bLoop = false;
|
|
m_Time = 0.0f;
|
|
}
|
|
|
|
CTexAnim::~CTexAnim()
|
|
{
|
|
for (uint32 i = 0; i < m_TexPics.Num(); i++)
|
|
{
|
|
ITexture* pTex = (ITexture*)m_TexPics[i];
|
|
SAFE_RELEASE(pTex);
|
|
}
|
|
m_TexPics.Free();
|
|
}
|
|
|
|
void CTexAnim::AddRef()
|
|
{
|
|
CryInterlockedIncrement(&m_nRefCount);
|
|
}
|
|
|
|
void CTexAnim::Release()
|
|
{
|
|
long refCnt = CryInterlockedDecrement(&m_nRefCount);
|
|
if (refCnt > 0)
|
|
{
|
|
return;
|
|
}
|
|
delete this;
|
|
}
|
|
|
|
int CTexAnim::Size() const
|
|
{
|
|
int nSize = sizeof(CTexAnim);
|
|
nSize += m_TexPics.GetMemoryUsage();
|
|
return nSize;
|
|
}
|