Merge remote-tracking branch 'public/release_candidate' into release
[CRYENGINE.git] / Code / CryEngine / RenderDll / Common / Textures / Texture.cpp
blob549739115d5e95fbff5ef4007bc7ad90dd2ffb4b
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 /*=============================================================================
4 Texture.cpp : Common texture manager implementation.
6 Revision history:
7 * Created by Honich Andrey
9 =============================================================================*/
11 #include "StdAfx.h"
12 #include <Cry3DEngine/ImageExtensionHelper.h>
13 #include "Image/CImage.h"
14 #include "Image/DDSImage.h"
15 #include "TextureManager.h"
16 #include <CrySystem/Scaleform/IFlashUI.h>
17 #include <CrySystem/File/IResourceManager.h>
18 #include <Cry3DEngine/I3DEngine.h>
19 #include <CryString/StringUtils.h> // stristr()
20 #include "TextureStreamPool.h"
21 #include "TextureHelpers.h"
22 #include <CrySystem/Scaleform/IUIFramework.h>
23 #include <CrySystem/Scaleform/IScaleformHelper.h>
25 // class CMipmapGenPass;
26 #include "../../XRenderD3D9/GraphicsPipeline/Common/UtilityPasses.h"
28 #define TEXTURE_LEVEL_CACHE_PAK "dds0.pak"
30 SSamplerState SSamplerState::s_sDefState;
32 int CTexture::s_nStreamingMode;
33 int CTexture::s_nStreamingUpdateMode;
34 bool CTexture::s_bPrecachePhase;
35 bool CTexture::s_bInLevelPhase = false;
36 bool CTexture::s_bPrestreamPhase;
38 size_t CTexture::s_nStreamingThroughput = 0;
39 float CTexture::s_nStreamingTotalTime = 0;
41 CTextureStreamPoolMgr* CTexture::s_pPoolMgr;
42 std::set<string> CTexture::s_vTexReloadRequests;
43 CryCriticalSection CTexture::s_xTexReloadLock;
44 #ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
45 CTexture::LowResSystemCopyType CTexture::s_LowResSystemCopy[TEX_SYS_COPY_MAX_SLOTS];
46 CryReadModifyLock CTexture::s_LowResSystemCopyLock;
47 #endif
49 #if defined(TEXSTRM_DEFERRED_UPLOAD)
50 ID3D11DeviceContext* CTexture::s_pStreamDeferredCtx = nullptr;
51 #endif
53 //============================================================
55 SResourceView SResourceView::ShaderResourceView(DXGI_FORMAT nFormat, int nFirstSlice, int nSliceCount, int nMostDetailedMip, int nMipCount, bool bSrgbRead, bool bMultisample, int nFlags)
57 SResourceView result(0);
59 result.m_Desc.eViewType = eShaderResourceView;
60 result.m_Desc.nFormat = nFormat;
61 result.m_Desc.nFirstSlice = nFirstSlice;
62 result.m_Desc.nSliceCount = nSliceCount;
63 result.m_Desc.nMostDetailedMip = nMostDetailedMip;
64 result.m_Desc.nMipCount = nMipCount;
65 result.m_Desc.bSrgbRead = bSrgbRead ? 1 : 0;
66 result.m_Desc.nFlags = nFlags;
67 result.m_Desc.bMultisample = bMultisample ? 1 : 0;
69 return result;
72 SResourceView SResourceView::RenderTargetView(DXGI_FORMAT nFormat, int nFirstSlice, int nSliceCount, int nMipLevel, bool bMultisample)
74 SResourceView result(0);
76 result.m_Desc.eViewType = eRenderTargetView;
77 result.m_Desc.nFormat = nFormat;
78 result.m_Desc.nFirstSlice = nFirstSlice;
79 result.m_Desc.nSliceCount = nSliceCount;
80 result.m_Desc.nMostDetailedMip = nMipLevel;
81 result.m_Desc.nMipCount = 1;
82 result.m_Desc.bMultisample = bMultisample ? 1 : 0;
84 return result;
87 SResourceView SResourceView::DepthStencilView(DXGI_FORMAT nFormat, int nFirstSlice, int nSliceCount, int nMipLevel, bool bMultisample, int nFlags)
89 SResourceView result(0);
91 result.m_Desc.eViewType = eDepthStencilView;
92 result.m_Desc.nFormat = nFormat;
93 result.m_Desc.nFirstSlice = nFirstSlice;
94 result.m_Desc.nSliceCount = nSliceCount;
95 result.m_Desc.nMostDetailedMip = nMipLevel;
96 result.m_Desc.nMipCount = 1;
97 result.m_Desc.nFlags = nFlags;
98 result.m_Desc.bMultisample = bMultisample ? 1 : 0;
100 return result;
103 SResourceView SResourceView::UnorderedAccessView(DXGI_FORMAT nFormat, int nFirstSlice, int nSliceCount, int nMipLevel, int nFlags)
105 SResourceView result(0);
107 result.m_Desc.eViewType = eUnorderedAccessView;
108 result.m_Desc.nFormat = nFormat;
109 result.m_Desc.nFirstSlice = nFirstSlice;
110 result.m_Desc.nSliceCount = nSliceCount;
111 result.m_Desc.nMostDetailedMip = nMipLevel;
112 result.m_Desc.nMipCount = 1;
113 result.m_Desc.nFlags = nFlags;
115 return result;
118 //============================================================
120 template<typename T>
121 static inline uint32 ConvertFromTextureFlags(ETextureFlags eFlags)
123 // NOTE Currently without correspondence:
125 // FT_DONT_RELEASE
126 // FT_USAGE_MSAA
127 // FT_FROMIMAGE
128 // FT_USAGE_ALLOWREADSRGB
130 // *INDENT-OFF*
131 return
132 (!(eFlags & FT_DONT_READ ) ? CDeviceObjectFactory::BIND_SHADER_RESOURCE : 0) |
133 ( (eFlags & FT_USAGE_RENDERTARGET ) ? CDeviceObjectFactory::BIND_RENDER_TARGET : 0) |
134 ( (eFlags & FT_USAGE_DEPTHSTENCIL ) ? CDeviceObjectFactory::BIND_DEPTH_STENCIL : 0) |
135 ( (eFlags & FT_USAGE_UNORDERED_ACCESS) ? CDeviceObjectFactory::BIND_UNORDERED_ACCESS : 0) |
136 (!(eFlags & FT_DONT_STREAM ) ? CDeviceObjectFactory::USAGE_STREAMING : 0) |
137 ( (eFlags & FT_STAGE_READBACK ) ? (CDeviceObjectFactory::USAGE_STAGE_ACCESS | CDeviceObjectFactory::USAGE_CPU_READ ) : 0) |
138 ( (eFlags & FT_STAGE_UPLOAD ) ? (CDeviceObjectFactory::USAGE_STAGE_ACCESS | CDeviceObjectFactory::USAGE_CPU_WRITE) : 0) |
139 ( (eFlags & FT_FORCE_MIPS ) ? CDeviceObjectFactory::USAGE_AUTOGENMIPS : 0) |
140 ( (eFlags & FT_USAGE_TEMPORARY ) ? CDeviceObjectFactory::USAGE_HIFREQ_HEAP : 0) |
141 ( (eFlags & FT_USAGE_UAV_OVERLAP ) ? CDeviceObjectFactory::USAGE_UAV_OVERLAP : 0) |
142 ( (eFlags & FT_USAGE_UAV_RWTEXTURE ) ? CDeviceObjectFactory::USAGE_UAV_READWRITE : 0);
143 // *INDENT-ON*
146 template<typename T>
147 static inline ETextureFlags ConvertToTextureFlags(uint32 eFlags)
149 // NOTE Currently without correspondence:
151 // FT_DONT_RELEASE
152 // FT_USAGE_MSAA
153 // FT_FROMIMAGE
154 // FT_USAGE_ALLOWREADSRGB
156 // *INDENT-OFF*
157 return ETextureFlags(
158 (!(eFlags & CDeviceObjectFactory::BIND_SHADER_RESOURCE ) ? FT_DONT_READ : 0) |
159 ( (eFlags & CDeviceObjectFactory::BIND_RENDER_TARGET ) ? FT_USAGE_RENDERTARGET : 0) |
160 ( (eFlags & CDeviceObjectFactory::BIND_DEPTH_STENCIL ) ? FT_USAGE_DEPTHSTENCIL : 0) |
161 ( (eFlags & CDeviceObjectFactory::BIND_UNORDERED_ACCESS ) ? FT_USAGE_UNORDERED_ACCESS : 0) |
162 (!(eFlags & CDeviceObjectFactory::USAGE_STREAMING ) ? FT_DONT_STREAM : 0) |
163 ( (eFlags & (CDeviceObjectFactory::USAGE_STAGE_ACCESS | CDeviceObjectFactory::USAGE_CPU_READ )) ? FT_STAGE_READBACK : 0) |
164 ( (eFlags & (CDeviceObjectFactory::USAGE_STAGE_ACCESS | CDeviceObjectFactory::USAGE_CPU_WRITE)) ? FT_STAGE_UPLOAD : 0) |
165 ( (eFlags & CDeviceObjectFactory::USAGE_AUTOGENMIPS ) ? FT_FORCE_MIPS : 0) |
166 ( (eFlags & CDeviceObjectFactory::USAGE_HIFREQ_HEAP ) ? FT_USAGE_TEMPORARY : 0) |
167 ( (eFlags & CDeviceObjectFactory::USAGE_UAV_OVERLAP ) ? FT_USAGE_UAV_OVERLAP : 0) |
168 ( (eFlags & CDeviceObjectFactory::USAGE_UAV_READWRITE ) ? FT_USAGE_UAV_RWTEXTURE : 0));
169 // *INDENT-ON*
172 //============================================================
173 CTexture::CTexture(const uint32 nFlags, const ColorF& clearColor /*= ColorF(Clr_Empty)*/, CDeviceTexture* devTexToOwn /*= nullptr*/)
175 m_eFlags = nFlags;
176 m_eDstFormat = eTF_Unknown;
177 m_eSrcFormat = eTF_Unknown;
178 m_nMips = 1;
179 m_nWidth = 0;
180 m_nHeight = 0;
181 m_eTT = eTT_2D;
182 m_nDepth = 1;
183 m_nArraySize = 1;
184 m_nDevTextureSize = 0;
185 m_fAvgBrightness = 1.0f;
186 m_cMinColor = 0.0f;
187 m_cMaxColor = 1.0f;
188 m_cClearColor = clearColor;
189 m_nPersistentSize = 0;
190 m_fAvgBrightness = 0.0f;
193 m_nUpdateFrameID = -1;
194 m_nAccessFrameID = -1;
195 m_nCustomID = -1;
196 m_pDevTexture = nullptr;
198 m_bIsLocked = false;
199 m_bNeedRestoring = false;
200 m_bNoTexture = false;
201 m_bResolved = true;
202 m_bUseMultisampledRTV = false;
203 m_bCustomFormat = false;
204 m_eSrcTileMode = eTM_Unspecified;
206 m_bPostponed = false;
207 m_bForceStreamHighRes = false;
208 m_bWasUnloaded = false;
209 m_bStreamed = false;
210 m_bStreamPrepared = false;
211 m_bStreamRequested = false;
212 m_bVertexTexture = false;
213 m_bUseDecalBorderCol = false;
214 m_bIsSRGB = false;
215 m_bNoDevTexture = false;
216 m_bInDistanceSortedList = false;
217 m_bCreatedInLevel = gRenDev->m_bInLevel;
218 m_bUsedRecently = 0;
219 m_bStatTracked = 0;
220 m_bStreamHighPriority = 0;
221 m_nStreamingPriority = 0;
222 m_nMinMipVidUploaded = MAX_MIP_LEVELS;
223 m_nMinMipVidActive = MAX_MIP_LEVELS;
224 m_nStreamSlot = InvalidStreamSlot;
225 m_fpMinMipCur = MAX_MIP_LEVELS << 8;
226 m_nStreamFormatCode = 0;
228 m_pFileTexMips = NULL;
229 m_fCurrentMipBias = 0.f;
231 static_assert(MaxStreamTasks < 32767, "Too many stream tasks!");
233 if (devTexToOwn)
235 OwnDevTexture(devTexToOwn);
239 //============================================================
241 CTexture::~CTexture()
243 InvalidateDeviceResource(this, eResourceDestroyed);
245 // sizes of these structures should NOT exceed L2 cache line!
246 static_assert((offsetof(CTexture, m_fCurrentMipBias) - offsetof(CTexture, m_pFileTexMips)) <= 64, "Invalid offset!");
248 CRY_ASSERT(gRenDev->m_pRT->IsRenderThread() && !gRenDev->m_pRT->IsRenderLoadingThread());
249 CRY_ASSERT(!IsStreaming());
251 ReleaseDeviceTexture(false);
253 if (m_pFileTexMips)
255 Unlink();
256 StreamState_ReleaseInfo(this, m_pFileTexMips);
257 m_pFileTexMips = NULL;
260 #ifdef ENABLE_TEXTURE_STREAM_LISTENER
261 if (s_pStreamListener)
262 s_pStreamListener->OnDestroyedStreamedTexture(this);
263 #endif
265 CRY_ASSERT(!m_bInDistanceSortedList);
267 #ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
269 AUTO_MODIFYLOCK(s_LowResSystemCopyLock);
271 for (int slot = 0; slot < TEX_SYS_COPY_MAX_SLOTS; slot++)
272 s_LowResSystemCopy[slot].erase(this);
274 #endif
277 const CCryNameTSCRC& CTexture::mfGetClassName()
279 return s_sClassName;
282 CCryNameTSCRC CTexture::GenName(const char* name, uint32 nFlags)
284 stack_string strName = name;
285 strName.MakeLower();
287 //'\\' in texture names causing duplication
288 PathUtil::ToUnixPath(strName);
290 if (nFlags & FT_ALPHA)
291 strName += "_a";
293 return CCryNameTSCRC(strName.c_str());
296 class StrComp
298 public:
299 bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; }
302 CTexture* CTexture::GetByID(int nID)
304 CTexture* pTex = CRendererResources::s_ptexNoTexture;
306 const CCryNameTSCRC& className = mfGetClassName();
307 CBaseResource* pBR = CBaseResource::GetResource(className, nID, false);
308 if (pBR)
309 pTex = (CTexture*)pBR;
310 return pTex;
313 CTexture* CTexture::GetByName(const char* szName, uint32 flags)
315 CTexture* pTex = nullptr;
317 CCryNameTSCRC Name = GenName(szName, flags);
318 CBaseResource* pBR = CBaseResource::GetResource(mfGetClassName(), Name, false);
319 if (pBR)
320 pTex = (CTexture*)pBR;
321 return pTex;
324 CTexture* CTexture::GetByNameCRC(CCryNameTSCRC Name)
326 CTexture* pTex = nullptr;
328 CBaseResource* pBR = CBaseResource::GetResource(mfGetClassName(), Name, false);
329 if (pBR)
330 pTex = (CTexture*)pBR;
331 return pTex;
334 CTexture* CTexture::FindOrRegisterTextureObject(const char* name, uint32 nFlags, ETEX_Format eTFDst, bool& bFound)
336 CTexture* pTex = nullptr;
338 CCryNameTSCRC Name = GenName(name, nFlags);
339 CBaseResource* pBR = CBaseResource::GetResource(mfGetClassName(), Name, false);
340 if (!pBR)
342 pTex = new CTexture(nFlags);
343 pTex->Register(mfGetClassName(), Name);
344 pTex->m_eFlags = nFlags;
345 pTex->m_eDstFormat = eTFDst;
346 pTex->m_SrcName = name;
347 bFound = false;
349 else
351 pTex = (CTexture*)pBR;
352 pTex->AddRef();
353 bFound = true;
356 return pTex;
359 void CTexture::RefDevTexture(CDeviceTexture* pDeviceTex)
361 // Hard-wired device-resources can't have a unique owner (they are shared)
362 if ((m_pDevTexture))
363 CRY_ASSERT(!DEVICE_TEXTURE_STORE_OWNER || m_pDevTexture->GetOwner() == nullptr);
365 if ((m_pDevTexture = pDeviceTex))
366 m_pDevTexture->SetOwner(nullptr, nullptr);
368 InvalidateDeviceResource(this, eDeviceResourceDirty);
371 void CTexture::SetDevTexture(CDeviceTexture* pDeviceTex)
373 // Substitute device-resource by a strictly subset one (texture-config doesn't change, only residency)
374 if ((m_pDevTexture))
376 CRY_ASSERT(!DEVICE_TEXTURE_STORE_OWNER || m_pDevTexture->GetOwner() == this);
377 m_pDevTexture->SetOwner(nullptr, nullptr);
378 m_pDevTexture->Release();
381 if ((m_pDevTexture = pDeviceTex))
383 m_pDevTexture->SetNoDelete(!!(m_eFlags & FT_DONT_RELEASE));
384 m_pDevTexture->SetOwner(this, m_SrcName.c_str());
386 m_nDevTextureSize = m_nPersistentSize = m_pDevTexture->GetDeviceSize();
389 InvalidateDeviceResource(this, eDeviceResourceDirty);
392 void CTexture::OwnDevTexture(CDeviceTexture* pDeviceTex)
394 // Take ownership of an entirely different device-resource (texture-config does change)
395 if ((m_pDevTexture))
397 CRY_ASSERT(!DEVICE_TEXTURE_STORE_OWNER || m_pDevTexture->GetOwner() == this);
398 m_pDevTexture->SetOwner(nullptr, nullptr);
399 m_pDevTexture->Release();
402 if ((m_pDevTexture = pDeviceTex))
404 m_pDevTexture->SetOwner(this, m_SrcName.c_str());
406 const STextureLayout Layput = m_pDevTexture->GetLayout();
408 m_nWidth = Layput.m_nWidth;
409 m_nHeight = Layput.m_nHeight;
410 m_nDepth = Layput.m_nDepth;
411 m_nArraySize = Layput.m_nArraySize;
412 m_nMips = Layput.m_nMips;
413 m_eSrcFormat = Layput.m_eSrcFormat;
414 m_eDstFormat = Layput.m_eDstFormat;
415 m_eTT = Layput.m_eTT;
416 m_eFlags = Layput.m_eFlags; /* TODO: change FT_... to CDeviceObjectFactory::... */
417 m_bIsSRGB = Layput.m_bIsSRGB;
419 m_nDevTextureSize = m_nPersistentSize = m_pDevTexture->GetDeviceSize();
422 InvalidateDeviceResource(this, eDeviceResourceDirty);
425 void CTexture::PostCreate()
427 m_nUpdateFrameID = gRenDev->m_pRT->IsRenderThread() ? gRenDev->GetRenderFrameID() : gRenDev->GetMainFrameID();
428 m_bPostponed = false;
431 void CTexture::GetMemoryUsage(ICrySizer* pSizer) const
433 pSizer->Add(*this);
434 pSizer->AddObject(m_SrcName);
436 #ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
438 AUTO_MODIFYLOCK(s_LowResSystemCopyLock);
440 for (int slot = 0; slot < TEX_SYS_COPY_MAX_SLOTS; slot++)
442 const LowResSystemCopyType::iterator& it = s_LowResSystemCopy[slot].find(this);
443 if (it != CTexture::s_LowResSystemCopy[slot].end())
444 pSizer->AddObject((*it).second.m_lowResSystemCopy);
447 #endif
449 if (m_pFileTexMips)
450 m_pFileTexMips->GetMemoryUsage(pSizer, m_nMips, m_CacheFileHeader.m_nSides);
453 //=======================================================
454 // Low-level functions calling CreateDeviceTexture()
456 void CTexture::CreateRenderTarget(ETEX_Format eFormat, const ColorF& cClear)
458 if (m_eSrcFormat == eTF_Unknown)
459 m_eSrcFormat = eFormat;
460 if (m_eSrcFormat == eTF_Unknown)
462 m_eFlags |= FT_FAILED;
463 return;
466 SetClosestFormatSupported();
467 m_eFlags |= FT_USAGE_RENDERTARGET;
468 m_cClearColor = cClear;
469 m_nMips = m_eFlags & FT_FORCE_MIPS ? CTexture::CalcNumMips(m_nWidth, m_nHeight) : m_nMips;
471 SSubresourceData pData(nullptr);
472 CreateDeviceTexture(std::move(pData));
473 PostCreate();
476 void CTexture::CreateDepthStencil(ETEX_Format eFormat, const ColorF& cClear)
478 if (m_eSrcFormat == eTF_Unknown)
479 m_eSrcFormat = eFormat;
480 if (m_eSrcFormat == eTF_Unknown)
482 m_eFlags |= FT_FAILED;
483 return;
486 SetClosestFormatSupported();
487 m_eFlags |= FT_USAGE_DEPTHSTENCIL;
488 m_cClearColor = cClear;
489 m_nMips = m_eFlags & FT_FORCE_MIPS ? CTexture::CalcNumMips(m_nWidth, m_nHeight) : m_nMips;
491 SSubresourceData pData(nullptr);
492 CreateDeviceTexture(std::move(pData));
493 PostCreate();
496 void CTexture::CreateShaderResource(STexDataPtr&& td)
498 m_nWidth = td->m_nWidth;
499 m_nHeight = td->m_nHeight;
500 m_nDepth = td->m_nDepth;
501 m_eSrcFormat = td->m_eFormat;
502 m_nMips = td->m_nMips;
503 m_fAvgBrightness = td->m_fAvgBrightness;
504 m_cMinColor = td->m_cMinColor;
505 m_cMaxColor = td->m_cMaxColor;
506 m_bUseDecalBorderCol = (td->m_nFlags & FIM_DECAL) != 0;
507 m_bIsSRGB = (td->m_nFlags & FIM_SRGB_READ) != 0;
509 assert((m_nDepth == 1) || (m_eTT == eTT_3D));
510 assert((m_nArraySize == 1) || (m_eTT == eTT_Cube || m_eTT == eTT_CubeArray || m_eTT == eTT_2DArray));
511 assert((m_nArraySize % 6) || (m_eTT == eTT_Cube || m_eTT == eTT_CubeArray));
512 assert(!td->m_pData[1] || !(m_eFlags & FT_REPLICATE_TO_ALL_SIDES) || (m_eTT == eTT_Cube || m_eTT == eTT_CubeArray));
513 assert(m_nWidth && m_nHeight && m_nMips);
515 SetClosestFormatSupported();
516 if (!(td = ImagePreprocessing(std::move(td), m_eDstFormat)))
518 SetNoTexture(m_eTT == eTT_Cube ? CRendererResources::s_ptexNoTextureCM : CRendererResources::s_ptexNoTexture);
519 delete td;
520 return;
523 #if defined(TEXTURE_GET_SYSTEM_COPY_SUPPORT)
524 if (m_eFlags & FT_KEEP_LOWRES_SYSCOPY)
526 uint16 width, height;
527 ITexture::GetLowResSystemCopy(width, height);
529 #endif
531 assert(m_nWidth && m_nHeight && m_nMips);
533 const int nMaxTextureSize = gRenDev->GetMaxTextureSize();
534 if (nMaxTextureSize > 0)
536 if (m_nWidth > nMaxTextureSize || m_nHeight > nMaxTextureSize)
538 SetNoTexture(m_eTT == eTT_Cube ? CRendererResources::s_ptexNoTextureCM : CRendererResources::s_ptexNoTexture);
539 delete td;
540 return;
544 SSubresourceData pData = td->Transfer();
545 CreateDeviceTexture(std::move(pData));
546 delete td;
549 //=======================================================
550 // Mid-level functions calling Create...()
552 void CTexture::Create2DTexture(int nWidth, int nHeight, int nMips, int nFlags, const byte* pSrcData, ETEX_Format eSrcFormat)
554 if (nMips <= 0)
555 nMips = CTexture::CalcNumMips(nWidth, nHeight);
556 m_eSrcTileMode = pSrcData ? eTM_None : eTM_Unspecified;
557 m_eSrcFormat = eSrcFormat;
558 m_nMips = nMips;
560 STexDataPtr td = new STexData;
562 td->m_eFormat = eSrcFormat;
563 td->m_eTileMode = m_eSrcTileMode;
564 td->m_nWidth = nWidth;
565 td->m_nHeight = nHeight;
566 td->m_nDepth = 1;
567 td->m_nMips = nMips;
568 td->m_pData[0] = pSrcData;
569 if (nFlags & FT_TAKEOVER_DATA_POINTER)
570 td->SetReallocated(0);
572 CreateShaderResource(std::move(td));
573 PostCreate();
576 void CTexture::Create3DTexture(int nWidth, int nHeight, int nDepth, int nMips, int nFlags, const byte* pSrcData, ETEX_Format eSrcFormat)
578 //if (nMips <= 0)
579 // nMips = CTexture::CalcNumMips(nWidth, nHeight);
580 m_eSrcTileMode = pSrcData ? eTM_None : eTM_Unspecified;
581 m_eSrcFormat = eSrcFormat;
582 m_nMips = nMips;
584 STexDataPtr td = new STexData;
586 td->m_eFormat = eSrcFormat;
587 td->m_eTileMode = m_eSrcTileMode;
588 td->m_nWidth = nWidth;
589 td->m_nHeight = nHeight;
590 td->m_nDepth = nDepth;
591 td->m_nMips = nMips;
592 td->m_pData[0] = pSrcData;
593 if (nFlags & FT_TAKEOVER_DATA_POINTER)
594 td->SetReallocated(0);
596 CreateShaderResource(std::move(td));
597 PostCreate();
600 //=======================================================
601 // High-level functions calling Create...()
603 CTexture* CTexture::GetOrCreateTextureObject(const char* name, uint32 nWidth, uint32 nHeight, int nDepth, ETEX_Type eTT, uint32 nFlags, ETEX_Format eFormat, int nCustomID)
605 SYNCHRONOUS_LOADING_TICK();
607 bool bFound = false;
609 MEMSTAT_CONTEXT(EMemStatContextType::Texture, name);
611 CTexture* pTex = FindOrRegisterTextureObject(name, nFlags, eFormat, bFound);
612 if (bFound)
614 if (pTex->m_nWidth == 0)
615 pTex->SetWidth(nWidth);
616 if (pTex->m_nHeight == 0)
617 pTex->SetHeight(nHeight);
619 pTex->m_nMips = nFlags & FT_FORCE_MIPS ? CTexture::CalcNumMips(pTex->m_nWidth, pTex->m_nHeight) : pTex->m_nMips;
620 pTex->m_eFlags |= nFlags & (FT_DONT_RELEASE | FT_USAGE_RENDERTARGET | FT_USAGE_DEPTHSTENCIL);
622 return pTex;
625 pTex->m_nDepth = nDepth;
626 pTex->SetWidth(nWidth);
627 pTex->SetHeight(nHeight);
628 pTex->m_nMips = nFlags & FT_FORCE_MIPS ? CTexture::CalcNumMips(pTex->m_nWidth, pTex->m_nHeight) : pTex->m_nMips;
629 pTex->m_eTT = eTT;
630 pTex->m_eSrcFormat = eFormat;
631 pTex->m_nCustomID = nCustomID;
632 pTex->m_SrcName = name;
633 pTex->SetClosestFormatSupported();
635 return pTex;
638 _smart_ptr<CTexture> CTexture::GetOrCreateTextureObjectPtr(const char* name, uint32 nWidth, uint32 nHeight, int nDepth, ETEX_Type eTT, uint32 nFlags, ETEX_Format eFormat, int nCustomID)
640 CTexture* pTex = GetOrCreateTextureObject(name, nWidth, nHeight, nDepth, eTT, nFlags, eFormat, nCustomID);
641 _smart_ptr<CTexture> result;
642 result.Assign_NoAddRef(pTex);
644 return result;
647 CTexture* CTexture::GetOrCreateTextureArray(const char* name, uint32 nWidth, uint32 nHeight, uint32 nArraySize, int nMips, ETEX_Type eType, uint32 nFlags, ETEX_Format eFormat, int nCustomID)
649 assert(eType == eTT_2DArray || eType == eTT_CubeArray);
651 if (nArraySize > 2048 /*D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION*/)
653 assert(0);
654 return NULL;
657 if (nMips <= 0)
658 nMips = CTexture::CalcNumMips(nWidth, nHeight);
660 bool sRGB = (nFlags & FT_USAGE_ALLOWREADSRGB) != 0;
661 nFlags &= ~FT_USAGE_ALLOWREADSRGB;
663 CTexture* pTex = GetOrCreateTextureObject(name, nWidth, nHeight, 1, eType, nFlags, eFormat, nCustomID);
665 pTex->SetWidth(nWidth);
666 pTex->SetHeight(nHeight);
667 pTex->m_nMips = nFlags & FT_FORCE_MIPS ? CTexture::CalcNumMips(pTex->m_nWidth, pTex->m_nHeight) : pTex->m_nMips;
668 pTex->m_nArraySize = nArraySize;
669 assert((eType != eTT_CubeArray) || !(nArraySize % 6));
670 pTex->m_nDepth = 1;
672 if (nFlags & FT_USAGE_RENDERTARGET)
674 pTex->CreateRenderTarget(eFormat, Clr_Unknown);
676 else if (nFlags & FT_USAGE_DEPTHSTENCIL)
678 pTex->CreateDepthStencil(eFormat, Clr_Unknown);
680 else
682 STexDataPtr td = new STexData;
684 td->m_eFormat = eFormat;
685 td->m_nDepth = 1;
686 td->m_nWidth = nWidth;
687 td->m_nHeight = nHeight;
688 td->m_nMips = nMips;
689 td->m_nFlags = sRGB ? FIM_SRGB_READ : 0;
691 pTex->CreateShaderResource(std::move(td));
694 pTex->PostCreate();
696 return pTex;
699 CTexture* CTexture::GetOrCreateRenderTarget(const char* name, uint32 nWidth, uint32 nHeight, const ColorF& cClear, ETEX_Type eTT, uint32 nFlags, ETEX_Format eFormat, int nCustomID)
701 CTexture* pTex = GetOrCreateTextureObject(name, nWidth, nHeight, 1, eTT, nFlags | FT_USAGE_RENDERTARGET, eFormat, nCustomID);
702 pTex->SetWidth(nWidth);
703 pTex->SetHeight(nHeight);
704 pTex->m_nMips = nFlags & FT_FORCE_MIPS ? CTexture::CalcNumMips(pTex->m_nWidth, pTex->m_nHeight) : pTex->m_nMips;
705 pTex->m_eFlags |= nFlags;
707 pTex->CreateRenderTarget(eFormat, cClear);
708 pTex->PostCreate();
710 return pTex;
713 _smart_ptr<CTexture> CTexture::GetOrCreateRenderTargetPtr(const char* name, uint32 nWidth, uint32 nHeight, const ColorF& cClear, ETEX_Type eTT, uint32 nFlags, ETEX_Format eFormat, int nCustomID)
715 CTexture* pTex = GetOrCreateRenderTarget(name, nWidth, nHeight, cClear, eTT, nFlags, eFormat, nCustomID);
716 _smart_ptr<CTexture> result;
717 result.Assign_NoAddRef(pTex);
719 return result;
722 CTexture* CTexture::GetOrCreateDepthStencil(const char* name, uint32 nWidth, uint32 nHeight, const ColorF& cClear, ETEX_Type eTT, uint32 nFlags, ETEX_Format eFormat, int nCustomID)
724 CTexture* pTex = GetOrCreateTextureObject(name, nWidth, nHeight, 1, eTT, nFlags | FT_USAGE_DEPTHSTENCIL, eFormat, nCustomID);
725 pTex->SetWidth(nWidth);
726 pTex->SetHeight(nHeight);
727 pTex->m_nMips = nFlags & FT_FORCE_MIPS ? CTexture::CalcNumMips(pTex->m_nWidth, pTex->m_nHeight) : pTex->m_nMips;
728 pTex->m_eFlags |= nFlags;
730 pTex->CreateDepthStencil(eFormat, cClear);
731 pTex->PostCreate();
733 return pTex;
736 _smart_ptr<CTexture> CTexture::GetOrCreateDepthStencilPtr(const char* name, uint32 nWidth, uint32 nHeight, const ColorF& cClear, ETEX_Type eTT, uint32 nFlags, ETEX_Format eFormat, int nCustomID)
738 CTexture* pTex = GetOrCreateDepthStencil(name, nWidth, nHeight, cClear, eTT, nFlags, eFormat, nCustomID);
739 _smart_ptr<CTexture> result;
740 result.Assign_NoAddRef(pTex);
742 return result;
745 CTexture* CTexture::GetOrCreate2DTexture(const char* szName, int nWidth, int nHeight, int nMips, int nFlags, const byte* pSrcData, ETEX_Format eSrcFormat, bool bAsyncDevTexCreation)
747 CRY_PROFILE_FUNCTION(PROFILE_RENDERER);
749 CTexture* pTex = GetOrCreateTextureObject(szName, nWidth, nHeight, 1, eTT_2D, nFlags, eSrcFormat, -1);
750 pTex->Create2DTexture(nWidth, nHeight, nMips, nFlags, pSrcData, eSrcFormat);
752 return pTex;
755 CTexture* CTexture::GetOrCreate3DTexture(const char* szName, int nWidth, int nHeight, int nDepth, int nMips, int nFlags, const byte* pSrcData, ETEX_Format eSrcFormat)
757 CTexture* pTex = GetOrCreateTextureObject(szName, nWidth, nHeight, nDepth, eTT_3D, nFlags, eSrcFormat, -1);
758 pTex->Create3DTexture(nWidth, nHeight, nDepth, nMips, nFlags, pSrcData, eSrcFormat);
760 return pTex;
763 //=======================================================
765 // This function tries to do the minimum amount of operations for events like SysSpec changes,
766 // where it's unclear which changes in the texture's state and residency are required to get
767 // from the old to the new spec.
768 void CTexture::Refresh()
770 if (IsStreamed())
772 AbortStreamingTasks(this);
774 // Demote streamed textures to their minimum persistent mips
775 // Configuration changes will stream the texture in with the final configurations.
776 int8 nKillMip = m_nMinMipVidUploaded;
777 int8 nKillPersMip = m_bForceStreamHighRes ? 0 : m_nMips - m_CacheFileHeader.m_nMipsPersistent;
779 if (nKillPersMip > nKillMip)
781 StreamTrim(nKillPersMip);
784 else
786 // Very difficult case, as CVars can clamp number of mips, and it's not anticipateable
787 // what the final calculated configurations for these textures are.
788 Reload();
792 void CTexture::Reload()
794 // If the texture is flagged to not be released, we skip the reloading
795 if (m_eFlags & FT_DONT_RELEASE)
796 return;
798 if (IsStreamed())
800 ReleaseDeviceTexture(false);
801 ToggleStreaming(true);
803 else
805 if (m_eFlags & (FT_USAGE_RENDERTARGET | FT_USAGE_DEPTHSTENCIL))
807 SSubresourceData pData(nullptr);
808 CreateDeviceTexture(std::move(pData));
810 else
812 LoadFromImage(m_SrcName.c_str());
816 PostCreate();
819 CTexture* CTexture::ForName(const char* name, uint32 nFlags, ETEX_Format eFormat)
821 SLICE_AND_SLEEP();
823 bool bFound = false;
825 MEMSTAT_CONTEXT(EMemStatContextType::Other, "Textures");
826 MEMSTAT_CONTEXT(EMemStatContextType::Texture, name);
828 CRY_DEFINE_ASSET_SCOPE("Texture", name);
830 CTexture* pTex = FindOrRegisterTextureObject(name, nFlags, eFormat, bFound);
831 if (bFound || name[0] == '$')
833 if (!bFound)
835 pTex->m_SrcName = name;
837 else
839 // switch off streaming for the same texture with the same flags except DONT_STREAM
840 if ((nFlags & FT_DONT_STREAM) != 0 && (pTex->GetFlags() & FT_DONT_STREAM) == 0)
842 if (!pTex->m_bPostponed)
843 pTex->ReleaseDeviceTexture(false);
844 pTex->m_eFlags |= FT_DONT_STREAM;
845 if (!pTex->m_bPostponed)
846 pTex->Reload();
850 return pTex;
852 pTex->m_SrcName = name;
854 #ifndef _RELEASE
855 pTex->m_sAssetScopeName = gEnv->pLog->GetAssetScopeString();
856 #endif
858 if (CTexture::s_bPrecachePhase || (pTex->m_eFlags & FT_ASYNC_PREPARE))
860 // NOTE: attached alpha isn't detectable by flags before the header is loaded, so we do it by file-suffix
861 if (/*(nFlags & FT_TEX_NORMAL_MAP) &&*/ TextureHelpers::VerifyTexSuffix(EFTT_NORMALS, name) && TextureHelpers::VerifyTexSuffix(EFTT_SMOOTHNESS, name))
862 nFlags |= FT_HAS_ATTACHED_ALPHA;
864 pTex->m_eDstFormat = eFormat;
865 pTex->m_eFlags = nFlags;
866 pTex->m_bPostponed = true;
867 pTex->m_bWasUnloaded = true;
870 if (!CTexture::s_bPrecachePhase)
871 pTex->Load(eFormat);
873 return pTex;
876 _smart_ptr<CTexture> CTexture::ForNamePtr(const char* name, uint32 nFlags, ETEX_Format eFormat)
878 CTexture* pTex = ForName(name, nFlags, eFormat);
879 _smart_ptr<CTexture> result;
880 result.Assign_NoAddRef(pTex);
882 return result;
885 struct CompareTextures
887 bool operator()(const CTexture* a, const CTexture* b)
889 return (stricmp(a->GetSourceName(), b->GetSourceName()) < 0);
893 void CTexture::Precache(const bool isBlocking)
895 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY)(iSystem);
897 if (!s_bPrecachePhase)
898 return;
899 if (!gRenDev)
900 return;
902 gEnv->pLog->UpdateLoadingScreen("Requesting textures precache ...");
904 gRenDev->ExecuteRenderThreadCommand( [isBlocking]{ CTexture::RT_Precache(isBlocking); },
905 ERenderCommandFlags::LevelLoadingThread_executeDirect
906 | (isBlocking ? ERenderCommandFlags::FlushAndWait : ERenderCommandFlags::None));
907 if (isBlocking)
909 gEnv->pLog->UpdateLoadingScreen("Textures precache done.");
913 void CTexture::RT_Precache(const bool isFinalPrecache)
915 CRY_PROFILE_FUNCTION(PROFILE_RENDERER);
917 // Disable invalid file access logging if texture streaming is disabled
918 // If texture streaming is turned off, we will hit this on the renderthread
919 // and stall due to the invalid file access stalls
920 ICVar* sysPakLogInvalidAccess = NULL;
921 int pakLogFileAccess = 0;
922 if (!CRenderer::CV_r_texturesstreaming)
924 if ((sysPakLogInvalidAccess = gEnv->pConsole->GetCVar("sys_PakLogInvalidFileAccess")))
926 pakLogFileAccess = sysPakLogInvalidAccess->GetIVal();
930 #if !defined(EXCLUDE_NORMAL_LOG)
931 CTimeValue t0 = gEnv->pTimer->GetAsyncTime();
932 #endif
934 CryLog("-- Precaching textures...");
935 iLog->UpdateLoadingScreen(0);
937 if (!gEnv->IsEditor())
938 CryLog("=============================== Loading textures ================================");
940 // Search texture(s) in a thread-safe manner, and protect the found texture(s) from deletion
941 // Loop should block the resource-library as briefly as possible (don't call heavy stuff in the loop)
942 std::forward_list<_smart_ptr<CTexture>> pFoundTextures;
943 size_t countableTextures = 0;
946 CryAutoReadLock<CryRWLock> lock(CBaseResource::s_cResLock);
948 SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
949 if (pRL)
951 ResourcesMapItor itor;
952 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
954 CTexture* pTexture = (CTexture*)itor->second;
955 if (!pTexture || !pTexture->CTexture::IsPostponed())
956 continue;
958 pFoundTextures.emplace_front(pTexture);
959 countableTextures++;
964 // Preload all the post poned textures
966 pFoundTextures.sort(CompareTextures());
968 gEnv->pSystem->GetStreamEngine()->PauseStreaming(false, 1 << eStreamTaskTypeTexture);
970 // Trigger the texture(s)'s load without holding the resource-library lock to evade dead-locks
972 int countedTextures = 0;
973 int numTextures = countableTextures;
974 int prevProgress = 0;
976 // TODO: jobbable
977 pFoundTextures.remove_if([&, numTextures](_smart_ptr<CTexture>& pTexture)
979 if (!pTexture->m_bStreamPrepared || !pTexture->IsStreamable())
981 pTexture->m_fpMinMipCur = MAX_MIP_LEVELS << 8;
982 pTexture->m_bPostponed = false;
983 pTexture->Load(pTexture->m_eDstFormat);
986 int progress = (++countedTextures * 10) / numTextures;
987 if (progress != prevProgress)
989 prevProgress = progress;
990 gEnv->pLog->UpdateLoadingScreen("Precaching progress: %d0.0%% (%d of %d)", progress, countedTextures, countableTextures);
993 // Only keep texture which really need Precache()
994 return !(pTexture->m_bStreamed && pTexture->m_bForceStreamHighRes);
999 CTimeValue time0 = iTimer->GetAsyncTime();
1001 while (s_StreamPrepTasks.GetNumLive())
1003 if (gRenDev->m_pRT->IsRenderThread() && !gRenDev->m_pRT->IsRenderLoadingThread() && !gRenDev->m_pRT->IsLevelLoadingThread())
1005 StreamState_Update();
1006 StreamState_UpdatePrep();
1008 else if (gRenDev->m_pRT->IsRenderLoadingThread() || gRenDev->m_pRT->IsLevelLoadingThread())
1010 StreamState_UpdatePrep();
1013 CrySleep(1);
1016 SRenderStatistics::Write().m_fTexUploadTime += (iTimer->GetAsyncTime() - time0).GetSeconds();
1019 // Trigger the texture(s)'s load without holding the resource-library lock to evade dead-locks
1021 // TODO: jobbable
1022 pFoundTextures.remove_if([](_smart_ptr<CTexture>& pTexture)
1024 pTexture->m_bStreamHighPriority |= 1;
1025 pTexture->m_fpMinMipCur = MAX_MIP_LEVELS << 8;
1027 s_pTextureStreamer->Precache(pTexture);
1029 return true;
1034 if (!gEnv->IsEditor())
1035 CryLog("========================== Finished loading textures ============================");
1037 #if !defined(EXCLUDE_NORMAL_LOG)
1038 CTimeValue t1 = gEnv->pTimer->GetAsyncTime();
1039 float dt = (t1 - t0).GetSeconds();
1040 CryLog("Precaching textures done in %.2f seconds", dt);
1041 #endif
1043 if (isFinalPrecache)
1045 s_bPrecachePhase = false;
1048 // Restore pakLogFileAccess if it was disabled during precaching
1049 // because texture precaching was disabled
1050 if (pakLogFileAccess)
1052 sysPakLogInvalidAccess->Set(pakLogFileAccess);
1056 void CTexture::Load(ETEX_Format eFormat)
1058 CRY_PROFILE_SECTION_ARG(PROFILE_LOADING_ONLY, "CTexture::Load(ETEX_Format eTFDst)", m_SrcName);
1059 m_bWasUnloaded = false;
1060 m_bStreamed = false;
1062 LoadFromImage(m_SrcName.c_str(), eFormat); // false=not reloading
1064 m_eFlags |= FT_FROMIMAGE;
1065 PostCreate();
1068 void CTexture::ToggleStreaming(const bool bEnable)
1070 if (!(m_eFlags & (FT_FROMIMAGE | FT_DONT_RELEASE)) || (m_eFlags & FT_DONT_STREAM))
1071 return;
1073 AbortStreamingTasks(this);
1074 if (bEnable)
1076 if (IsStreamed())
1077 return;
1079 ReleaseDeviceTexture(false);
1080 m_bStreamed = true;
1081 if (StreamPrepare(true))
1082 return;
1084 if (m_pFileTexMips)
1086 Unlink();
1087 StreamState_ReleaseInfo(this, m_pFileTexMips);
1088 m_pFileTexMips = NULL;
1091 m_bStreamed = false;
1092 if (m_bNoTexture)
1093 return;
1096 ReleaseDeviceTexture(false);
1097 Reload();
1100 void CTexture::LoadFromImage(const char* name, ETEX_Format eFormat)
1102 CRY_PROFILE_FUNCTION_ARG(PROFILE_LOADING_ONLY, name);
1104 if (CRenderer::CV_r_texnoload && SetNoTexture())
1105 return;
1107 string sFileName(name);
1108 sFileName.MakeLower();
1110 m_eDstFormat = eFormat;
1112 // try to stream-in the texture
1113 if (IsStreamable())
1115 m_bStreamed = true;
1116 if (StreamPrepare(true))
1118 assert(m_pDevTexture);
1119 return;
1122 m_eFlags |= FT_DONT_STREAM;
1123 m_bStreamed = false;
1124 m_bForceStreamHighRes = false;
1125 if (m_bNoTexture)
1127 if (m_pFileTexMips)
1129 Unlink();
1130 StreamState_ReleaseInfo(this, m_pFileTexMips);
1131 m_pFileTexMips = NULL;
1132 m_bStreamed = false;
1137 #ifndef _RELEASE
1138 CRY_DEFINE_ASSET_SCOPE("Texture", m_sAssetScopeName);
1139 #endif
1141 if (m_bPostponed)
1143 if (s_pTextureStreamer->BeginPrepare(this, sFileName, (m_eFlags & FT_ALPHA) ? FIM_ALPHA : 0))
1144 return;
1147 uint32 nImageFlags =
1148 ((m_eFlags & FT_ALPHA) ? FIM_ALPHA : 0) |
1149 ((m_eFlags & FT_STREAMED_PREPARE) ? FIM_READ_VIA_STREAMS : 0) |
1150 ((m_eFlags & FT_DONT_STREAM) ? FIM_IMMEDIATE_RC : 0);
1152 Load(CImageFile::mfLoad_file(sFileName, nImageFlags));
1155 void CTexture::Load(CImageFilePtr&& pImage)
1157 if (!pImage || pImage->mfGetFormat() == eTF_Unknown)
1159 SetNoTexture(m_eTT == eTT_Cube ? CRendererResources::s_ptexNoTextureCM : CRendererResources::s_ptexNoTexture);
1160 return;
1163 //CRY_PROFILE_SECTION_ARG(PROFILE_LOADING_ONLY, "CTexture::Load(CImageFile* pImage)", pImage->mfGet_filename().c_str());
1165 if ((m_eFlags & FT_ALPHA) && !pImage->mfIs_image(0))
1167 SetNoTexture(CRendererResources::s_ptexWhite);
1168 return;
1171 const char* name = pImage->mfGet_filename().c_str();
1172 if (pImage->mfGet_Flags() & FIM_SPLITTED) // propagate splitted file flag
1173 m_eFlags |= FT_SPLITTED;
1174 if (pImage->mfGet_Flags() & FIM_FILESINGLE) // propagate flag from image to texture
1175 m_eFlags |= FT_FILESINGLE;
1176 if (pImage->mfGet_Flags() & FIM_NORMALMAP)
1178 if (!(m_eFlags & FT_TEX_NORMAL_MAP) && !CryStringUtils::stristr(name, "_ddn"))
1180 // becomes reported as editor error
1181 gEnv->pSystem->Warning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE,
1182 name, "Not a normal map texture attempted to be used as a normal map: %s", name);
1186 if (!(m_eFlags & FT_ALPHA) && !(
1187 pImage->mfGetFormat() == eTF_BC5U || pImage->mfGetFormat() == eTF_BC5S || pImage->mfGetFormat() == eTF_BC7 ||
1188 pImage->mfGetFormat() == eTF_EAC_RG11 || pImage->mfGetFormat() == eTF_EAC_RG11S
1189 ) && CryStringUtils::stristr(name, "_ddn") != 0 && GetDevTexture()) // improvable code
1191 // becomes reported as editor error
1192 gEnv->pSystem->Warning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE,
1193 name, "Wrong format '%s' for normal map texture '%s'", CTexture::GetFormatName(), name);
1196 if (pImage->mfGet_Flags() & FIM_NOTSUPPORTS_MIPS && !(m_eFlags & FT_NOMIPS))
1197 m_eFlags |= FT_FORCE_MIPS;
1198 if (pImage->mfGet_Flags() & FIM_HAS_ATTACHED_ALPHA)
1199 m_eFlags |= FT_HAS_ATTACHED_ALPHA; // if the image has alpha attached we store this in the CTexture
1201 m_eSrcTileMode = pImage->mfGetTileMode();
1202 m_nArraySize = pImage->mfGet_NumSides();
1203 m_eTT =
1204 (pImage->mfGet_depth() > 1) ? eTT_3D :
1205 (pImage->mfGet_NumSides() == 6) ? eTT_Cube :
1206 !(pImage->mfGet_NumSides() % 6) ? eTT_CubeArray :
1207 (pImage->mfGet_NumSides() == 1) ? eTT_2D :
1208 eTT_2DArray;
1210 STexDataPtr td = new STexData;
1212 td->m_nFlags = pImage->mfGet_Flags();
1213 td->m_nWidth = pImage->mfGet_width();
1214 td->m_nHeight = pImage->mfGet_height();
1215 td->m_nDepth = pImage->mfGet_depth();
1216 td->m_eFormat = pImage->mfGetFormat();
1217 td->m_eTileMode = pImage->mfGetTileMode();
1218 td->m_nMips = pImage->mfGet_numMips();
1219 td->m_fAvgBrightness = pImage->mfGet_avgBrightness();
1220 td->m_cMinColor = pImage->mfGet_minColor();
1221 td->m_cMaxColor = pImage->mfGet_maxColor();
1222 if ((m_eFlags & FT_NOMIPS) || td->m_nMips <= 0)
1223 td->m_nMips = 1;
1224 td->m_pFilePath = pImage->mfGet_filename();
1226 // base range after normalization, fe. [0,1] for 8bit images, or [0,2^15] for RGBE/HDR data
1227 if (CImageExtensionHelper::IsDynamicRange(td->m_eFormat))
1229 td->m_cMinColor /= td->m_cMaxColor.a;
1230 td->m_cMaxColor /= td->m_cMaxColor.a;
1233 // Move data-pointer from Image into TexData
1234 for (int i = 0, j = !pImage->mfIs_image(1) ? 1 : 6; i < j; i++)
1236 td->AssignData(i, pImage->mfGet_image(i, true));
1239 CreateShaderResource(std::move(CTexture::FormatFixup(std::move(td))));
1242 void CTexture::UpdateData(STexDataPtr&& td, int flags)
1244 m_eFlags = flags;
1245 m_eDstFormat = td->m_eFormat;
1247 CreateShaderResource(std::move(td));
1250 ETEX_Format CTexture::FormatFixup(ETEX_Format eFormat)
1252 switch (eFormat)
1254 case eTF_L8V8U8X8:
1255 case eTF_L8V8U8:
1256 return eTF_R8G8B8A8S;
1257 case eTF_B8G8R8:
1258 case eTF_A8L8:
1259 case eTF_L8:
1260 return eTF_R8G8B8A8;
1262 // only available as hardware format under DX11.1 with DXGI 1.2
1263 case eTF_B5G5R5A1:
1264 case eTF_B5G6R5:
1265 case eTF_B4G4R4A4:
1267 //! Only available as hardware format under Vulkan or XBO.
1268 case eTF_R4G4:
1269 case eTF_R4G4B4A4:
1271 const SPixFormat* pPF;
1272 return CTexture::GetClosestFormatSupported(eFormat, pPF);
1275 default:
1276 return eFormat;
1280 STexDataPtr CTexture::FormatFixup(STexDataPtr&& td)
1282 const ETEX_Format eSrcFormat = td->m_eFormat;
1283 const ETEX_Format eDstFormat = FormatFixup(eSrcFormat);
1284 CRY_ASSERT(eDstFormat != eTF_Unknown);
1286 if (td->m_eTileMode == eTM_None)
1288 // Try and expand
1289 uint32 nSourceSize = CTexture::TextureDataSize(td->m_nWidth, td->m_nHeight, td->m_nDepth, td->m_nMips, 1, eSrcFormat, eTM_None);
1290 uint32 nTargetSize = CTexture::TextureDataSize(td->m_nWidth, td->m_nHeight, td->m_nDepth, td->m_nMips, 1, eDstFormat, eTM_None);
1292 for (int nImage = 0; nImage < sizeof(td->m_pData) / sizeof(td->m_pData[0]); ++nImage)
1294 if (td->m_pData[nImage])
1296 byte* pNewImage = new byte[nTargetSize];
1297 CTexture::ExpandMipFromFile(pNewImage, nTargetSize, td->m_pData[nImage], nSourceSize, eSrcFormat, eDstFormat);
1298 td->AssignData(nImage, pNewImage);
1302 td->m_eFormat = eDstFormat;
1304 else
1306 CRY_ASSERT(eDstFormat == eSrcFormat);
1309 return td;
1312 STexDataPtr CTexture::ImagePreprocessing(STexDataPtr&& td, ETEX_Format eDstFormat)
1314 CRY_PROFILE_FUNCTION(PROFILE_RENDERER);
1316 #if !defined(_RELEASE)
1317 const char* pTexFileName = td->m_pFilePath ? td->m_pFilePath : "$Unknown";
1318 #endif
1320 if (eDstFormat == eTF_Unknown)
1322 // NOTE: leaks memory
1323 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;
1325 #if !defined(_RELEASE)
1326 TextureError(pTexFileName, "Trying to process a texture with unsupported target format %s->unknown!", NameForTextureFormat(td->m_eFormat));
1327 #endif
1328 return nullptr;
1331 const ETEX_Format eSrcFormat = td->m_eFormat;
1332 const bool fmtConversionNeeded = eSrcFormat != eDstFormat;
1334 #if !CRY_PLATFORM_WINDOWS
1335 if (fmtConversionNeeded)
1337 // NOTE: leaks memory
1338 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;
1340 #if !defined(_RELEASE)
1341 TextureError(pTexFileName, "Trying an image format conversion from %s to %s. This is not supported on this platform!", NameForTextureFormat(eSrcFormat), NameForTextureFormat(eDstFormat));
1342 #endif
1343 return nullptr;
1345 #else
1347 const bool doProcessing = fmtConversionNeeded;
1348 if (doProcessing)
1350 const int nSrcWidth = td->m_nWidth;
1351 const int nSrcHeight = td->m_nHeight;
1353 for (int i = 0; i < 6; i++)
1355 if (const byte* pSrcData = td->m_pData[i])
1357 uint32 nOutSize = 0;
1358 const byte* pNewData = Convert(pSrcData, nSrcWidth, nSrcHeight, td->m_nMips, eSrcFormat, eDstFormat, td->m_nMips, nOutSize, true);
1359 if (pNewData)
1360 td->AssignData(i, pNewData);
1364 td->m_eFormat = eDstFormat;
1366 #endif
1368 return td;
1371 int8 CTexture::CalcNumMips(int nWidth, int nHeight)
1373 int8 nMips = 0;
1374 while (nWidth || nHeight)
1376 if (!nWidth) nWidth = 1;
1377 if (!nHeight) nHeight = 1;
1378 nWidth >>= 1;
1379 nHeight >>= 1;
1380 nMips++;
1382 return nMips;
1385 uint32 CTexture::TextureDataSize(uint32 nWidth, uint32 nHeight, uint32 nDepth, int8 nMips, uint32 nSlices, const ETEX_Format eTF, ETEX_TileMode eTM)
1387 FUNCTION_PROFILER_RENDERER();
1389 // Don't allow 0 dimensions, it's clearly wrong to reflect on "unspecified-yet" textures.
1390 CRY_ASSERT(eTF != eTF_Unknown && nWidth && nHeight && nDepth);
1391 // Allow 0 mips and 0 slices to generate offsets with this function.
1392 if (!nMips || !nSlices)
1393 return 0;
1395 const bool bIsBlockCompressed = IsBlockCompressed(eTF);
1396 nWidth = max(1U, nWidth);
1397 nHeight = max(1U, nHeight);
1398 nDepth = max(1U, nDepth);
1400 if (eTM != eTM_None)
1402 // NOTE: Using this function to acquire strides of elements or rows (and even slices in arrays),
1403 // is not yielding any usable information. In the moment the clients need to be aware that
1404 // the internal layout for tiled modes can't be interpreted and stay away from it.
1405 // TODO: Create separate interfaces for sub-resource size queries and for layout-stride queries
1407 #if CRY_PLATFORM_ORBIS
1408 if (bIsBlockCompressed)
1410 nWidth = ((nWidth + 3) & (-4));
1411 nHeight = ((nHeight + 3) & (-4));
1413 #endif
1415 #if CRY_PLATFORM_CONSOLE
1416 return CDeviceTexture::TextureDataSize(nWidth, nHeight, nDepth, nMips, nSlices, eTF, eTM, CDeviceObjectFactory::BIND_SHADER_RESOURCE);
1417 #endif
1421 const uint32 nBytesPerElement = bIsBlockCompressed ? BytesPerBlock(eTF) : BytesPerPixel(eTF);
1423 uint32 nSize = 0;
1424 while ((nWidth || nHeight || nDepth) && nMips)
1426 nWidth = max(1U, nWidth);
1427 nHeight = max(1U, nHeight);
1428 nDepth = max(1U, nDepth);
1430 uint32 nU = nWidth;
1431 uint32 nV = nHeight;
1432 uint32 nW = nDepth;
1434 if (bIsBlockCompressed)
1436 // depth is not 4x4x4 compressed, but 4x4x1
1437 nU = ((nWidth + 3) / (4));
1438 nV = ((nHeight + 3) / (4));
1441 nSize += nU * nV * nW * nBytesPerElement;
1443 nWidth >>= 1;
1444 nHeight >>= 1;
1445 nDepth >>= 1;
1447 --nMips;
1450 return nSize * nSlices;
1454 bool CTexture::IsInPlaceFormat(const ETEX_Format fmt)
1456 switch (fmt)
1458 case eTF_R8G8B8A8S:
1459 case eTF_R8G8B8A8:
1461 case eTF_R1:
1462 case eTF_A8:
1463 case eTF_R8:
1464 case eTF_R8S:
1465 case eTF_R16:
1466 case eTF_R16S:
1467 case eTF_R16F:
1468 case eTF_R32F:
1469 case eTF_R8G8:
1470 case eTF_R8G8S:
1471 case eTF_R16G16:
1472 case eTF_R16G16S:
1473 case eTF_R16G16F:
1474 case eTF_R32G32F:
1475 case eTF_R11G11B10F:
1476 case eTF_R10G10B10A2:
1477 case eTF_R16G16B16A16:
1478 case eTF_R16G16B16A16S:
1479 case eTF_R16G16B16A16F:
1480 case eTF_R32G32B32A32F:
1482 case eTF_BC1:
1483 case eTF_BC2:
1484 case eTF_BC3:
1485 case eTF_BC4U:
1486 case eTF_BC4S:
1487 case eTF_BC5U:
1488 case eTF_BC5S:
1489 #if defined(CRY_DDS_DX10_SUPPORT)
1490 case eTF_BC6UH:
1491 case eTF_BC6SH:
1492 case eTF_BC7:
1493 case eTF_R9G9B9E5:
1494 #endif
1495 case eTF_CTX1:
1496 case eTF_EAC_R11:
1497 case eTF_EAC_R11S:
1498 case eTF_EAC_RG11:
1499 case eTF_EAC_RG11S:
1500 case eTF_ETC2:
1501 case eTF_ETC2A:
1502 case eTF_ASTC_LDR_4x4:
1504 case eTF_B8G8R8A8:
1505 case eTF_B8G8R8X8:
1506 return true;
1507 default:
1508 return false;
1512 void CTexture::ExpandMipFromFile(byte* dst, const uint32 dstSize, const byte* src, const uint32 srcSize, const ETEX_Format eSrcFormat, const ETEX_Format eDstFormat)
1514 if (IsInPlaceFormat(eSrcFormat))
1516 assert(dstSize == srcSize);
1517 if (dst != src)
1519 memcpy(dst, src, srcSize);
1522 return;
1525 // upload mip from file with conversions depending on format and platform specifics
1526 switch (eSrcFormat)
1528 case eTF_B8G8R8: // -> eTF_R8G8B8A8
1529 assert(eDstFormat == eTF_R8G8B8A8);
1531 for (ptrdiff_t i = ptrdiff_t(srcSize / 3) - 1; i >= 0; --i)
1533 dst[i * 4 + 0] = src[i * 3 + 2];
1534 dst[i * 4 + 1] = src[i * 3 + 1];
1535 dst[i * 4 + 2] = src[i * 3 + 0];
1536 dst[i * 4 + 3] = 255;
1539 break;
1540 case eTF_L8V8U8X8: // -> eTF_R8G8B8A8S
1541 assert(eDstFormat == eTF_R8G8B8A8S);
1543 for (ptrdiff_t i = ptrdiff_t(srcSize / 4) - 1; i >= 0; --i)
1545 dst[i * 4 + 0] = src[i * 3 + 0];
1546 dst[i * 4 + 1] = src[i * 3 + 1];
1547 dst[i * 4 + 2] = src[i * 3 + 2];
1548 dst[i * 4 + 3] = src[i * 3 + 3];
1551 break;
1552 case eTF_L8V8U8: // -> eTF_R8G8B8A8S
1553 assert(eDstFormat == eTF_R8G8B8A8S);
1555 for (ptrdiff_t i = ptrdiff_t(srcSize / 3) - 1; i >= 0; --i)
1557 dst[i * 4 + 0] = src[i * 3 + 0];
1558 dst[i * 4 + 1] = src[i * 3 + 1];
1559 dst[i * 4 + 2] = src[i * 3 + 2];
1560 dst[i * 4 + 3] = 255;
1563 break;
1564 case eTF_L8: // -> eTF_R8G8B8A8
1565 assert(eDstFormat == eTF_R8G8B8A8);
1567 for (ptrdiff_t i = ptrdiff_t(srcSize) - 1; i >= 0; --i)
1569 const byte bSrc = src[i];
1570 dst[i * 4 + 0] = bSrc;
1571 dst[i * 4 + 1] = bSrc;
1572 dst[i * 4 + 2] = bSrc;
1573 dst[i * 4 + 3] = 255;
1576 break;
1577 case eTF_A8L8: // -> eTF_R8G8B8A8
1578 assert(eDstFormat == eTF_R8G8B8A8);
1580 for (ptrdiff_t i = ptrdiff_t(srcSize) - 1; i >= 0; i -= 2)
1582 const byte bSrcL = src[i - 1];
1583 const byte bSrcA = src[i - 0];
1584 dst[i * 4 + 0] = bSrcL;
1585 dst[i * 4 + 1] = bSrcL;
1586 dst[i * 4 + 2] = bSrcL;
1587 dst[i * 4 + 3] = bSrcA;
1590 break;
1592 case eTF_B5G5R5A1: // -> eTF_B8G8R8A8
1593 assert(eDstFormat == eTF_B8G8R8A8);
1595 for (ptrdiff_t i = ptrdiff_t(srcSize / 2) - 1; i >= 0; --i)
1597 const uint16 rgb5551 = uint16((src[i * 2 + 0] << 8) + src[i * 2 + 1]);
1598 dst[i * 4 + 0] = ((rgb5551 >> 0) * 33) >> 2;
1599 dst[i * 4 + 1] = ((rgb5551 >> 5) * 33) >> 2;
1600 dst[i * 4 + 2] = ((rgb5551 >> 10) * 33) >> 2;
1601 dst[i * 4 + 3] = ((rgb5551 >> 15) ? 255 : 0);
1604 break;
1605 case eTF_B5G6R5: // -> eTF_B8G8R8X8
1606 assert(eDstFormat == eTF_B8G8R8X8);
1608 for (ptrdiff_t i = ptrdiff_t(srcSize / 2) - 1; i >= 0; --i)
1610 const uint16 rgb565 = uint16((src[i * 2 + 0] << 8) + src[i * 2 + 1]);
1611 dst[i * 4 + 0] = ((rgb565 >> 0) * 33) >> 2;
1612 dst[i * 4 + 1] = ((rgb565 >> 5) * 65) >> 4;
1613 dst[i * 4 + 2] = ((rgb565 >> 11) * 33) >> 2;
1614 dst[i * 4 + 3] = 255;
1617 break;
1618 case eTF_B4G4R4A4: // -> eTF_B8G8R8A8
1619 case eTF_R4G4B4A4: // -> eTF_R8G8B8A8
1620 assert((eSrcFormat == eTF_B4G4R4A4 && eDstFormat == eTF_B8G8R8A8) ||
1621 (eSrcFormat == eTF_R4G4B4A4 && eDstFormat == eTF_R8G8B8A8));
1623 for (ptrdiff_t i = ptrdiff_t(srcSize / 2) - 1; i >= 0; --i)
1625 const uint16 rgb4444 = uint16((src[i * 2 + 0] << 8) + src[i * 2 + 1]);
1626 dst[i * 4 + 0] = (rgb4444 >> 0) * 17;
1627 dst[i * 4 + 1] = (rgb4444 >> 4) * 17;
1628 dst[i * 4 + 2] = (rgb4444 >> 8) * 17;
1629 dst[i * 4 + 3] = (rgb4444 >> 12) * 17;
1632 break;
1633 case eTF_R4G4: // -> eTF_R8G8|eTF_R8G8B8A8
1634 assert(eDstFormat == eTF_R8G8 || eDstFormat == eTF_R8G8B8A8);
1635 if (eDstFormat == eTF_R8G8)
1637 for (ptrdiff_t i = ptrdiff_t(srcSize / 1) - 1; i >= 0; --i)
1639 const uint8 rgb44 = uint8(src[i * 1 + 0]);
1640 dst[i * 2 + 0] = (rgb44 >> 0) * 17;
1641 dst[i * 2 + 1] = (rgb44 >> 4) * 17;
1644 else
1646 for (ptrdiff_t i = ptrdiff_t(srcSize / 1) - 1; i >= 0; --i)
1648 const uint8 rgb44 = uint8(src[i * 1 + 0]);
1649 dst[i * 4 + 0] = (rgb44 >> 0) * 17;
1650 dst[i * 4 + 1] = (rgb44 >> 4) * 17;
1651 dst[i * 4 + 2] = 0;
1652 dst[i * 4 + 3] = 255;
1655 break;
1657 default:
1658 assert(0);
1662 bool CTexture::Invalidate(int nNewWidth, int nNewHeight, ETEX_Format eNewFormat)
1664 bool bRelease = false;
1665 if (nNewWidth > 0 && nNewWidth != m_nWidth)
1667 m_nWidth = nNewWidth;
1668 bRelease = true;
1670 if (nNewHeight > 0 && nNewHeight != m_nHeight)
1672 m_nHeight = nNewHeight;
1673 bRelease = true;
1675 if (eNewFormat != eTF_Unknown && eNewFormat != m_eSrcFormat)
1677 m_eSrcFormat = eNewFormat;
1678 SetClosestFormatSupported();
1680 bRelease = true;
1683 if (!m_pDevTexture)
1684 return false;
1686 if (bRelease)
1688 if (m_eFlags & FT_FORCE_MIPS)
1689 m_nMips = 1;
1691 ReleaseDeviceTexture(true);
1694 return bRelease;
1697 D3DBaseView* CTexture::GetResourceView(const SResourceView& rvDesc)
1699 if (CDeviceTexture* pDevTex = GetDevTexture(rvDesc.m_Desc.bMultisample))
1701 ResourceViewHandle hView = pDevTex->GetOrCreateResourceViewHandle(rvDesc);
1702 return pDevTex->LookupResourceView(hView).second;
1705 return nullptr;
1708 D3DBaseView* CTexture::GetResourceView(const SResourceView& rvDesc) const
1710 if (CDeviceTexture* pDevTex = GetDevTexture(rvDesc.m_Desc.bMultisample))
1712 ResourceViewHandle hView = pDevTex->GetResourceViewHandle(rvDesc);
1713 if (hView != ResourceViewHandle::Unspecified)
1714 return pDevTex->LookupResourceView(hView).second;
1717 return nullptr;
1720 void CTexture::SetResourceView(const SResourceView& rvDesc, D3DBaseView* pView)
1722 if (CDeviceTexture* pDevTex = GetDevTexture(rvDesc.m_Desc.bMultisample))
1724 ResourceViewHandle hView = pDevTex->GetResourceViewHandle(rvDesc);
1725 if (hView != ResourceViewHandle::Unspecified)
1727 SAFE_RELEASE(pDevTex->LookupResourceView(hView).second);
1729 pDevTex->LookupResourceView(hView).second = pView;
1730 pDevTex->LookupResourceView(hView).second->AddRef();
1735 void CTexture::SetDefaultShaderResourceView(D3DBaseView* pDeviceShaderResource, bool bMultisampled /*= false*/)
1737 CDeviceTexture* pDevTex = GetDevTexture(bMultisampled && IsMSAA());
1739 SAFE_RELEASE(pDevTex->LookupResourceView(EDefaultResourceViews::Default).second);
1741 pDevTex->LookupResourceView(EDefaultResourceViews::Default).second = pDeviceShaderResource;
1742 pDevTex->LookupResourceView(EDefaultResourceViews::Default).second->AddRef();
1744 // Notify that resource is dirty
1745 if (!(m_eFlags & FT_USAGE_RENDERTARGET))
1747 InvalidateDeviceResource(this, eDeviceResourceViewDirty);
1751 byte* CTexture::GetData32(int nSide, int nLevel, byte* pDstData, ETEX_Format eDstFormat)
1753 #if CRY_PLATFORM_WINDOWS
1754 // NOTE: the function will not maintain any dirty state and always download the data, don't use it in the render-loop
1755 CDeviceTexture* pDevTexture = GetDevTexture();
1756 pDevTexture->DownloadToStagingResource(D3D11CalcSubresource(nLevel, nSide, m_nMips), [&](void* pData, uint32 rowPitch, uint32 slicePitch)
1758 if (m_eDstFormat != eTF_R8G8B8A8)
1760 uint32 nOutSize = 0;
1762 if (m_eSrcFormat == eDstFormat && pDstData)
1764 memcpy(pDstData, pData, GetDeviceDataSize());
1766 else
1768 pDstData = (byte*)Convert((byte*)pData, m_nWidth, m_nHeight, 1, m_eSrcFormat, eDstFormat, 1, nOutSize, true);
1771 else
1773 if (!pDstData)
1775 pDstData = new byte[m_nWidth * m_nHeight * 4];
1778 memcpy(pDstData, pData, m_nWidth * m_nHeight * 4);
1781 return true;
1784 return pDstData;
1785 #else
1786 return 0;
1787 #endif
1790 const size_t CTexture::GetAllocatedSystemMemory(bool bIncludePool, bool bIncludeCache) const
1792 size_t nSize = sizeof(*this);
1793 nSize += m_SrcName.capacity();
1795 // TODO: neccessary?
1796 // if (m_pRenderTargetData)
1797 // {
1798 // nSize += sizeof(*m_pRenderTargetData);
1799 // nSize += m_pRenderTargetData->m_DirtyRects.capacity() * sizeof(RECT);
1800 // }
1802 if (m_pFileTexMips)
1804 if (bIncludeCache)
1805 nSize += m_pFileTexMips->GetAllocatedSystemMemory(m_nMips, m_CacheFileHeader.m_nSides);
1806 if (bIncludePool && m_pFileTexMips->m_pPoolItem)
1807 nSize += m_pFileTexMips->m_pPoolItem->GetAllocatedSystemMemory();
1810 return nSize;
1813 void CTexture::Init()
1815 SDynTexture::Init();
1816 InitStreaming();
1819 void CTexture::PostInit()
1821 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY);
1824 int __cdecl TexCallback(const VOID* arg1, const VOID* arg2)
1826 CTexture** pi1 = (CTexture**)arg1;
1827 CTexture** pi2 = (CTexture**)arg2;
1828 CTexture* ti1 = *pi1;
1829 CTexture* ti2 = *pi2;
1831 if (ti1->GetDeviceDataSize() > ti2->GetDeviceDataSize())
1832 return -1;
1833 if (ti1->GetDeviceDataSize() < ti2->GetDeviceDataSize())
1834 return 1;
1835 return stricmp(ti1->GetSourceName(), ti2->GetSourceName());
1838 int __cdecl TexCallbackMips(const VOID* arg1, const VOID* arg2)
1840 CTexture** pi1 = (CTexture**)arg1;
1841 CTexture** pi2 = (CTexture**)arg2;
1842 CTexture* ti1 = *pi1;
1843 CTexture* ti2 = *pi2;
1845 int nSize1, nSize2;
1847 nSize1 = ti1->GetActualSize();
1848 nSize2 = ti2->GetActualSize();
1850 if (nSize1 > nSize2)
1851 return -1;
1852 if (nSize1 < nSize2)
1853 return 1;
1854 return stricmp(ti1->GetSourceName(), ti2->GetSourceName());
1857 void CTexture::Update()
1859 FUNCTION_PROFILER_RENDERER();
1861 // reload pending texture reload requests
1863 std::set<string> queue;
1865 s_xTexReloadLock.Lock();
1866 s_vTexReloadRequests.swap(queue);
1867 s_xTexReloadLock.Unlock();
1869 // TODO: jobbable
1870 for (std::set<string>::iterator i = queue.begin(); i != queue.end(); ++i)
1871 ReloadFile(*i);
1874 CTexture::s_bStreamingFromHDD = gEnv->pSystem->GetStreamEngine()->IsStreamDataOnHDD();
1875 CTexture::s_nStatsStreamPoolInUseMem = CTexture::s_pPoolMgr->GetInUseSize();
1877 s_pTextureStreamer->ApplySchedule(ITextureStreamer::eASF_Full);
1878 s_pTextureStreamer->BeginUpdateSchedule();
1880 #ifdef ENABLE_TEXTURE_STREAM_LISTENER
1881 StreamUpdateStats();
1882 #endif
1884 SDynTexture::Tick();
1886 if ((s_nStreamingMode != CRenderer::CV_r_texturesstreaming) || (s_nStreamingUpdateMode != CRenderer::CV_r_texturesstreamingUpdateType))
1888 InitStreaming();
1891 #ifndef CONSOLE_CONST_CVAR_MODE
1892 char buf[256] = "";
1894 if (CRenderer::CV_r_texlog)
1896 CryAutoReadLock<CryRWLock> lock(CBaseResource::s_cResLock);
1898 SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
1899 ResourcesMapItor itor;
1901 uint32 i;
1902 if (pRL && (CRenderer::CV_r_texlog == 2 || CRenderer::CV_r_texlog == 3 || CRenderer::CV_r_texlog == 4))
1904 FILE* fp = NULL;
1905 TArray<CTexture*> Texs;
1906 int Size = 0;
1907 int PartSize = 0;
1908 if (CRenderer::CV_r_texlog == 2 || CRenderer::CV_r_texlog == 3)
1910 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
1912 CTexture* tp = (CTexture*)itor->second;
1913 if (CRenderer::CV_r_texlog == 3 && tp->IsNoTexture())
1915 Texs.AddElem(tp);
1917 else if (CRenderer::CV_r_texlog == 2 && !tp->IsNoTexture() && tp->m_pFileTexMips) // (tp->GetFlags() & FT_FROMIMAGE))
1919 Texs.AddElem(tp);
1922 if (CRenderer::CV_r_texlog == 3)
1924 CryLogAlways("Logging to MissingTextures.txt...");
1925 fp = fxopen("MissingTextures.txt", "w");
1927 else
1929 CryLogAlways("Logging to UsedTextures.txt...");
1930 fp = fxopen("UsedTextures.txt", "w");
1932 fprintf(fp, "*** All textures: ***\n");
1934 if (Texs.Num())
1935 qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallbackMips);
1937 for (i = 0; i < Texs.Num(); i++)
1939 int w = Texs[i]->GetWidth();
1940 int h = Texs[i]->GetHeight();
1942 size_t nTSize = Texs[i]->m_pFileTexMips->GetAllocatedSystemMemory(Texs[i]->GetNumMips(), Texs[i]->GetNumSides());
1944 fprintf(fp, "%" PRISIZE_T "\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());
1945 //Size += Texs[i]->GetDataSize();
1946 Size += nTSize;
1948 PartSize += Texs[i]->GetDeviceDataSize();
1950 fprintf(fp, "*** Total Size: %d\n\n", Size /*, PartSize, PartSize */);
1952 Texs.Free();
1954 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
1956 CTexture* tp = (CTexture*)itor->second;
1957 if (tp->m_nAccessFrameID == gRenDev->GetMainFrameID())
1959 Texs.AddElem(tp);
1963 if (fp)
1965 fclose(fp);
1966 fp = 0;
1969 fp = fxopen("UsedTextures_Frame.txt", "w");
1971 if (fp)
1972 fprintf(fp, "\n\n*** Textures used in current frame: ***\n");
1973 else
1974 IRenderAuxText::TextToScreenColor(4, 13, 1, 1, 0, 1, "*** Textures used in current frame: ***");
1975 int nY = 17;
1977 if (Texs.Num())
1978 qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallback);
1980 Size = 0;
1981 for (i = 0; i < Texs.Num(); i++)
1983 if (fp)
1984 fprintf(fp, "%.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());
1985 else
1987 cry_sprintf(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());
1988 IRenderAuxText::TextToScreenColor(4, nY, 0, 1, 0, 1, buf);
1989 nY += 3;
1991 PartSize += Texs[i]->GetDeviceDataSize();
1992 Size += Texs[i]->GetDataSize();
1994 if (fp)
1996 fprintf(fp, "*** Total Size: %.3fMb, Device Size: %.3fMb\n\n", Size / (1024.0f * 1024.0f), PartSize / (1024.0f * 1024.0f));
1998 else
2000 cry_sprintf(buf, "*** Total Size: %.3fMb, Device Size: %.3fMb", Size / (1024.0f * 1024.0f), PartSize / (1024.0f * 1024.0f));
2001 IRenderAuxText::TextToScreenColor(4, nY + 1, 0, 1, 1, 1, buf);
2004 Texs.Free();
2005 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
2007 CTexture* tp = (CTexture*)itor->second;
2008 if (tp && !tp->IsNoTexture())
2010 Texs.AddElem(tp);
2014 if (fp)
2016 fclose(fp);
2017 fp = 0;
2019 fp = fxopen("UsedTextures_All.txt", "w");
2021 if (fp)
2022 fprintf(fp, "\n\n*** All Existing Textures: ***\n");
2023 else
2024 IRenderAuxText::TextToScreenColor(4, 13, 1, 1, 0, 1, "*** Textures loaded: ***");
2026 if (Texs.Num())
2027 qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallback);
2029 Size = 0;
2030 for (i = 0; i < Texs.Num(); i++)
2032 if (fp)
2034 int w = Texs[i]->GetWidth();
2035 int h = Texs[i]->GetHeight();
2036 fprintf(fp, "%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());
2038 else
2040 cry_sprintf(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());
2041 IRenderAuxText::TextToScreenColor(4, nY, 0, 1, 0, 1, buf);
2042 nY += 3;
2044 Size += Texs[i]->GetDeviceDataSize();
2046 if (fp)
2048 fprintf(fp, "*** Total Size: %.3fMb\n\n", Size / (1024.0f * 1024.0f));
2050 else
2052 cry_sprintf(buf, "*** Total Size: %.3fMb", Size / (1024.0f * 1024.0f));
2053 IRenderAuxText::TextToScreenColor(4, nY + 1, 0, 1, 1, 1, buf);
2056 Texs.Free();
2057 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
2059 CTexture* tp = (CTexture*)itor->second;
2060 if (tp && !tp->IsNoTexture() && !tp->IsStreamed())
2062 Texs.AddElem(tp);
2066 if (fp)
2068 fclose(fp);
2069 fp = 0;
2072 if (CRenderer::CV_r_texlog != 4)
2073 CRenderer::CV_r_texlog = 0;
2075 else if (pRL && (CRenderer::CV_r_texlog == 1))
2077 //char *str = GetTexturesStatusText();
2079 TArray<CTexture*> Texs;
2080 //TArray<CTexture *> TexsNM;
2081 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
2083 CTexture* tp = (CTexture*)itor->second;
2084 if (tp && !tp->IsNoTexture())
2086 Texs.AddElem(tp);
2087 //if (tp->GetFlags() & FT_TEX_NORMAL_MAP)
2088 // TexsNM.AddElem(tp);
2092 if (Texs.Num())
2093 qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallback);
2095 int64 AllSize = 0;
2096 int64 Size = 0;
2097 int64 PartSize = 0;
2098 int64 NonStrSize = 0;
2099 int nNoStr = 0;
2100 int64 SizeNM = 0;
2101 int64 SizeDynCom = 0;
2102 int64 SizeDynAtl = 0;
2103 int64 PartSizeNM = 0;
2104 int nNumTex = 0;
2105 int nNumTexNM = 0;
2106 int nNumTexDynAtl = 0;
2107 int nNumTexDynCom = 0;
2108 for (i = 0; i < Texs.Num(); i++)
2110 CTexture* tex = Texs[i];
2111 const uint32 texFlags = tex->GetFlags();
2112 const int texDataSize = tex->GetDataSize();
2113 const int texDeviceDataSize = tex->GetDeviceDataSize();
2115 if (tex->GetDevTexture() && !(texFlags & FT_USAGE_RENDERTARGET))
2117 AllSize += texDataSize;
2118 if (!Texs[i]->IsStreamed())
2120 NonStrSize += texDataSize;
2121 nNoStr++;
2125 if (texFlags & FT_USAGE_RENDERTARGET)
2127 if (texFlags & FT_USAGE_ATLAS)
2129 ++nNumTexDynAtl;
2130 SizeDynAtl += texDataSize;
2132 else
2134 ++nNumTexDynCom;
2135 SizeDynCom += texDataSize;
2138 else if (0 == (texFlags & FT_TEX_NORMAL_MAP))
2140 if (!Texs[i]->IsUnloaded())
2142 ++nNumTex;
2143 Size += texDataSize;
2144 PartSize += texDeviceDataSize;
2147 else
2149 if (!Texs[i]->IsUnloaded())
2151 ++nNumTexNM;
2152 SizeNM += texDataSize;
2153 PartSizeNM += texDeviceDataSize;
2158 cry_sprintf(buf, "All texture objects: %u (Size: %.3fMb), NonStreamed: %d (Size: %.3fMb)", Texs.Num(), AllSize / (1024.0 * 1024.0), nNoStr, NonStrSize / (1024.0 * 1024.0));
2159 IRenderAuxText::TextToScreenColor(4, 13, 1, 1, 0, 1, buf);
2160 cry_sprintf(buf, "All Loaded Texture Maps: %d (All MIPS: %.3fMb, Loaded MIPS: %.3fMb)", nNumTex, Size / (1024.0f * 1024.0f), PartSize / (1024.0 * 1024.0));
2161 IRenderAuxText::TextToScreenColor(4, 16, 1, 1, 0, 1, buf);
2162 cry_sprintf(buf, "All Loaded Normal Maps: %d (All MIPS: %.3fMb, Loaded MIPS: %.3fMb)", nNumTexNM, SizeNM / (1024.0 * 1024.0), PartSizeNM / (1024.0 * 1024.0));
2163 IRenderAuxText::TextToScreenColor(4, 19, 1, 1, 0, 1, buf);
2164 cry_sprintf(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));
2165 IRenderAuxText::TextToScreenColor(4, 22, 1, 1, 0, 1, buf);
2167 Texs.Free();
2168 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
2170 CTexture* tp = (CTexture*)itor->second;
2171 if (tp && !tp->IsNoTexture() && tp->m_nAccessFrameID == gRenDev->GetMainFrameID())
2173 Texs.AddElem(tp);
2177 if (Texs.Num())
2178 qsort(&Texs[0], Texs.Num(), sizeof(CTexture*), TexCallback);
2180 Size = 0;
2181 SizeDynAtl = 0;
2182 SizeDynCom = 0;
2183 PartSize = 0;
2184 NonStrSize = 0;
2185 for (i = 0; i < Texs.Num(); i++)
2187 Size += Texs[i]->GetDataSize();
2188 if (Texs[i]->GetFlags() & FT_USAGE_RENDERTARGET)
2190 if (Texs[i]->GetFlags() & FT_USAGE_ATLAS)
2191 SizeDynAtl += Texs[i]->GetDataSize();
2192 else
2193 SizeDynCom += Texs[i]->GetDataSize();
2195 else
2196 PartSize += Texs[i]->GetDeviceDataSize();
2197 if (!Texs[i]->IsStreamed())
2198 NonStrSize += Texs[i]->GetDataSize();
2200 cry_sprintf(buf, "Current tex. objects: %u (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));
2201 IRenderAuxText::TextToScreenColor(4, 27, 1, 0, 0, 1, buf);
2204 #endif
2207 void CTexture::RT_LoadingUpdate()
2209 CTexture::s_bStreamingFromHDD = gEnv->pSystem->GetStreamEngine()->IsStreamDataOnHDD();
2210 CTexture::s_nStatsStreamPoolInUseMem = CTexture::s_pPoolMgr->GetInUseSize();
2212 ITextureStreamer::EApplyScheduleFlags asf = CTexture::s_bPrecachePhase
2213 ? ITextureStreamer::eASF_InOut // Exclude the prep update, as it will be done by the RLT (and can be expensive)
2214 : ITextureStreamer::eASF_Full;
2216 s_pTextureStreamer->ApplySchedule(asf);
2219 void CTexture::RLT_LoadingUpdate()
2221 s_pTextureStreamer->BeginUpdateSchedule();
2224 //=========================================================================
2226 void CTexture::ShutDown()
2228 RT_FlushAllStreamingTasks(true);
2230 if (s_pStatsTexWantedLists)
2232 for (int i = 0; i < 2; ++i)
2233 s_pStatsTexWantedLists[i].clear();
2236 if (CRenderer::CV_r_releaseallresourcesonexit)
2238 SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
2239 if (pRL)
2241 int n = 0;
2242 ResourcesMapItor itor;
2243 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); )
2245 CTexture* pTX = (CTexture*)itor->second;
2246 itor++;
2247 if (!pTX)
2248 continue;
2249 if (CRenderer::CV_r_printmemoryleaks)
2250 iLog->Log("Warning: CTexture::ShutDown: Texture %s was not deleted (%d)", pTX->GetName(), pTX->GetRefCounter());
2251 SAFE_RELEASE_FORCE(pTX);
2252 n++;
2257 s_pPoolMgr->Flush();
2260 void CTexture::ReloadFile_Request(const char* szFileName)
2262 s_xTexReloadLock.Lock();
2263 s_vTexReloadRequests.insert(szFileName);
2264 s_xTexReloadLock.Unlock();
2267 void CTexture::ReloadFile(const char* szFileName) threadsafe
2269 FUNCTION_PROFILER_RENDERER();
2271 char gameFolderPath[256];
2272 cry_strcpy(gameFolderPath, PathUtil::GetGameFolder());
2273 PREFAST_SUPPRESS_WARNING(6054); // it is nullterminated
2274 int gameFolderPathLength = strlen(gameFolderPath);
2275 if (gameFolderPathLength > 0 && gameFolderPath[gameFolderPathLength - 1] == '\\')
2277 gameFolderPath[gameFolderPathLength - 1] = '/';
2279 else if (gameFolderPathLength > 0 && gameFolderPath[gameFolderPathLength - 1] != '/')
2281 gameFolderPath[gameFolderPathLength++] = '/';
2282 gameFolderPath[gameFolderPathLength] = 0;
2285 string realName = PathUtil::ToUnixPath(szFileName);
2286 if (realName.size() >= (uint32)gameFolderPathLength && memcmp(realName.data(), gameFolderPath, gameFolderPathLength) == 0)
2287 realName += gameFolderPathLength;
2289 CCryNameTSCRC crc32NameBase = GenName(realName, 0);
2290 CCryNameTSCRC crc32NameAtch = GenName(realName, FT_ALPHA);
2292 // Search texture in a thread-safe manner, and protect the found texture from deletion
2293 _smart_ptr<CTexture> pFoundTextureBase = nullptr;
2294 _smart_ptr<CTexture> pFoundTextureAtch = nullptr;
2297 CryAutoReadLock<CryRWLock> lock(s_cResLock);
2299 SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
2300 if (pRL)
2302 const auto& itorBase = pRL->m_RMap.find(crc32NameBase);
2303 const auto& itorAtch = pRL->m_RMap.find(crc32NameAtch);
2305 if (itorBase != pRL->m_RMap.end())
2306 pFoundTextureBase = (CTexture*)itorBase->second;
2307 if (itorAtch != pRL->m_RMap.end())
2308 pFoundTextureAtch = (CTexture*)itorAtch->second;
2312 // Trigger the texture's reload without holding the resource-library lock to evade dead-locks
2313 if (pFoundTextureBase)
2314 pFoundTextureBase->Reload();
2315 if (pFoundTextureAtch)
2316 pFoundTextureAtch->Reload();
2319 void CTexture::ReloadTextures() threadsafe
2321 gRenDev->ExecuteRenderThreadCommand([]{ CTexture::RT_ReloadTextures(); }, ERenderCommandFlags::LevelLoadingThread_executeDirect);
2324 void CTexture::RT_ReloadTextures()
2326 FUNCTION_PROFILER_RENDERER();
2328 // Flush any outstanding texture requests before reloading
2329 CTexture::RT_FlushStreaming(true);
2331 std::forward_list<_smart_ptr<CTexture>> pFoundTextures;
2333 // Search texture(s) in a thread-safe manner, and protect the found texture(s) from deletion
2334 // Loop should block the resource-library as briefly as possible (don't call heavy stuff in the loop)
2336 CryAutoReadLock<CryRWLock> lock(CBaseResource::s_cResLock);
2338 SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
2339 if (pRL)
2341 ResourcesMapItor itor;
2342 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
2344 CTexture* pTexture = (CTexture*)itor->second;
2345 if (!pTexture || !(pTexture->m_eFlags & FT_FROMIMAGE))
2346 continue;
2348 pFoundTextures.emplace_front(pTexture);
2353 // Trigger the texture(s)'s reload without holding the resource-library lock to evade dead-locks
2355 // TODO: jobbable
2356 pFoundTextures.remove_if([](_smart_ptr<CTexture>& pTexture) { pTexture->Reload(); return true; });
2360 void CTexture::RefreshTextures() threadsafe
2362 gRenDev->ExecuteRenderThreadCommand([]{ CTexture::RT_RefreshTextures(); }, ERenderCommandFlags::LevelLoadingThread_executeDirect);
2365 void CTexture::RT_RefreshTextures()
2367 FUNCTION_PROFILER_RENDERER();
2369 // Flush any outstanding texture requests before reloading
2370 CTexture::RT_FlushStreaming(true);
2372 std::forward_list<_smart_ptr<CTexture>> pFoundTextures;
2374 // Search texture(s) in a thread-safe manner, and protect the found texture(s) from deletion
2375 // Loop should block the resource-library as briefly as possible (don't call heavy stuff in the loop)
2377 CryAutoReadLock<CryRWLock> lock(CBaseResource::s_cResLock);
2379 SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
2380 if (pRL)
2382 ResourcesMapItor itor;
2383 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
2385 CTexture* pTexture = (CTexture*)itor->second;
2386 if (!pTexture || !(pTexture->m_eFlags & FT_FROMIMAGE))
2387 continue;
2389 pFoundTextures.emplace_front(pTexture);
2394 // Trigger the texture(s)'s refresh without holding the resource-library lock to evade dead-locks
2396 // TODO: jobbable
2397 pFoundTextures.remove_if([](_smart_ptr<CTexture>& pTexture) { pTexture->Refresh(); return true; });
2401 void CTexture::ToggleTexturesStreaming() threadsafe
2403 gRenDev->ExecuteRenderThreadCommand([]{ CTexture::RT_ToggleTexturesStreaming(); }, ERenderCommandFlags::LevelLoadingThread_executeDirect);
2406 void CTexture::RT_ToggleTexturesStreaming()
2408 FUNCTION_PROFILER_RENDERER();
2410 // Flush any outstanding texture requests before reloading
2411 CTexture::RT_FlushStreaming(true);
2413 std::forward_list<_smart_ptr<CTexture>> pFoundTextures;
2415 // Search texture(s) in a thread-safe manner, and protect the found texture(s) from deletion
2416 // Loop should block the resource-library as briefly as possible (don't call heavy stuff in the loop)
2418 CryAutoReadLock<CryRWLock> lock(CBaseResource::s_cResLock);
2420 SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
2421 if (pRL)
2423 ResourcesMapItor itor;
2424 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
2426 CTexture* pTexture = (CTexture*)itor->second;
2427 if (!pTexture || !(pTexture->m_eFlags & FT_FROMIMAGE))
2428 continue;
2430 pFoundTextures.emplace_front(pTexture);
2435 // Trigger the texture(s)'s reload without holding the resource-library lock to evade dead-locks
2437 // TODO: jobbable
2438 pFoundTextures.remove_if([](_smart_ptr<CTexture>& pTexture) { pTexture->ToggleStreaming(CRenderer::CV_r_texturesstreaming != 0); return true; });
2442 void CTexture::LogTextures(ILog* pLog) threadsafe
2444 std::forward_list<_smart_ptr<CTexture>> pFoundTextures;
2446 // Search texture(s) in a thread-safe manner, and protect the found texture(s) from deletion
2447 // Loop should block the resource-library as briefly as possible (don't call heavy stuff in the loop)
2449 CryAutoReadLock<CryRWLock> lock(CBaseResource::s_cResLock);
2451 SResourceContainer* pRL = CBaseResource::GetResourcesForClass(CTexture::mfGetClassName());
2452 if (pRL)
2454 ResourcesMapItor itor;
2455 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
2457 CTexture* pTexture = (CTexture*)itor->second;
2458 if (!pTexture)
2459 continue;
2460 const char* pName = pTexture->GetName();
2461 if (!pName || strchr(pName, '/'))
2462 continue;
2464 pFoundTextures.emplace_front(pTexture);
2469 // Trigger the texture(s)'s reload without holding the resource-library lock to evade dead-locks
2471 pFoundTextures.remove_if([](_smart_ptr<CTexture>& pTexture) { iLog->Log("\t%s -- fmt: %s, dim: %d x %d\n", pTexture->GetName(), pTexture->GetFormatName(), pTexture->GetWidth(), pTexture->GetHeight()); return true; });
2475 bool CTexture::SetNoTexture(CTexture* pDefaultTexture /* = s_ptexNoTexture*/)
2477 m_eFlags |= FT_FAILED;
2479 if (pDefaultTexture)
2481 RefDevTexture(pDefaultTexture->GetDevTexture());
2483 m_eSrcFormat = pDefaultTexture->GetSrcFormat();
2484 m_eDstFormat = pDefaultTexture->GetDstFormat();
2485 m_nMips = pDefaultTexture->GetNumMips();
2486 m_nWidth = pDefaultTexture->GetWidth();
2487 m_nHeight = pDefaultTexture->GetHeight();
2488 m_nDepth = 1;
2489 m_fAvgBrightness = 1.0f;
2490 m_cMinColor = 0.0f;
2491 m_cMaxColor = 1.0f;
2492 m_cClearColor = ColorF(0.0f, 0.0f, 0.0f, 1.0f);
2494 m_bNoTexture = true;
2495 if (m_pFileTexMips)
2497 Unlink();
2498 StreamState_ReleaseInfo(this, m_pFileTexMips);
2499 m_pFileTexMips = NULL;
2502 m_bStreamed = false;
2503 m_bPostponed = false;
2505 m_nDevTextureSize = 0;
2506 m_nPersistentSize = 0;
2508 return true;
2511 return false;
2514 //////////////////////////////////////////////////////////////////////////
2515 const char* CTexture::GetFormatName() const
2517 return NameForTextureFormat(GetDstFormat());
2520 //////////////////////////////////////////////////////////////////////////
2521 const char* CTexture::GetTypeName() const
2523 return NameForTextureType(GetTextureType());
2526 struct FlashTextureSourceSharedRT_AutoUpdate
2528 public:
2529 static void Add(CFlashTextureSourceBase* pSrc)
2531 CryAutoCriticalSection lock(ms_lock);
2532 stl::push_back_unique(ms_sources, pSrc);
2535 static void AddToLightList(CFlashTextureSourceBase* pSrc)
2537 if (stl::find(ms_LightTextures, pSrc)) return;
2538 ms_LightTextures.push_back(pSrc);
2541 static void Remove(CFlashTextureSourceBase* pSrc)
2543 CryAutoCriticalSection lock(ms_lock);
2545 const size_t size = ms_sources.size();
2546 for (size_t i = 0; i < size; ++i)
2548 if (ms_sources[i] == pSrc)
2550 ms_sources[i] = ms_sources[size - 1];
2551 ms_sources.pop_back();
2552 if (ms_sources.empty())
2554 stl::reconstruct(ms_sources);
2556 break;
2559 stl::find_and_erase(ms_LightTextures, pSrc);
2562 static void Tick()
2564 SRenderThread* pRT = gRenDev->m_pRT;
2565 if (!pRT || (pRT->IsMainThread() && pRT->m_eVideoThreadMode == SRenderThread::eVTM_Disabled))
2567 CTimeValue curTime = gEnv->pTimer->GetAsyncTime();
2568 const int frameID = gRenDev->GetMainFrameID();
2569 if (ms_lastTickFrameID != frameID)
2571 CryAutoCriticalSection lock(ms_lock);
2573 const float deltaTime = gEnv->pTimer->GetFrameTime();
2574 const bool isEditing = gEnv->IsEditing();
2575 const bool isPaused = gEnv->pSystem->IsPaused();
2577 const size_t size = ms_sources.size();
2578 for (size_t i = 0; i < size; ++i)
2580 ms_sources[i]->AutoUpdate(curTime, deltaTime, isEditing, isPaused);
2583 ms_lastTickFrameID = frameID;
2588 static void TickRT()
2590 SRenderThread* pRT = gRenDev->m_pRT;
2591 if (!pRT || (pRT->IsRenderThread() && pRT->m_eVideoThreadMode == SRenderThread::eVTM_Disabled))
2593 const int frameID = gRenDev->GetRenderFrameID();
2594 if (ms_lastTickRTFrameID != frameID)
2596 CryAutoCriticalSection lock(ms_lock);
2598 const size_t size = ms_sources.size();
2599 for (size_t i = 0; i < size; ++i)
2601 ms_sources[i]->AutoUpdateRT(frameID);
2604 ms_lastTickRTFrameID = frameID;
2609 static void RenderLightTextures()
2611 for (std::vector<CFlashTextureSourceBase*>::const_iterator it = ms_LightTextures.begin(); it != ms_LightTextures.end(); ++it)
2612 (*it)->Update();
2613 ms_LightTextures.clear();
2616 private:
2617 static std::vector<CFlashTextureSourceBase*> ms_sources;
2618 static std::vector<CFlashTextureSourceBase*> ms_LightTextures;
2619 static CryCriticalSection ms_lock;
2620 static int ms_lastTickFrameID;
2621 static int ms_lastTickRTFrameID;
2624 void CFlashTextureSourceBase::Tick()
2626 FlashTextureSourceSharedRT_AutoUpdate::Tick();
2629 void CFlashTextureSourceBase::TickRT()
2631 FlashTextureSourceSharedRT_AutoUpdate::TickRT();
2634 void CFlashTextureSourceBase::RenderLights()
2636 FlashTextureSourceSharedRT_AutoUpdate::RenderLightTextures();
2639 void CFlashTextureSourceBase::AddToLightRenderList(const IDynTextureSource* pSrc)
2641 FlashTextureSourceSharedRT_AutoUpdate::AddToLightList((CFlashTextureSourceBase*)pSrc);
2644 void CFlashTextureSourceBase::AutoUpdate(const CTimeValue& curTime, const float delta, const bool isEditing, const bool isPaused)
2646 if (m_autoUpdate)
2648 m_pFlashPlayer->UpdatePlayer(this);
2649 #if CRY_PLATFORM_WINDOWS
2650 m_perFrameRendering &= !isEditing;
2651 #endif
2653 if (m_perFrameRendering || (curTime - m_lastVisible).GetSeconds() < 1.0f)
2655 Advance(delta, isPaused);
2660 void CFlashTextureSourceBase::AutoUpdateRT(const int frameID)
2662 if (m_autoUpdate)
2664 if (m_perFrameRendering && (frameID != m_lastVisibleFrameID))
2666 Update();
2671 std::vector<CFlashTextureSourceBase*> FlashTextureSourceSharedRT_AutoUpdate::ms_sources;
2672 std::vector<CFlashTextureSourceBase*> FlashTextureSourceSharedRT_AutoUpdate::ms_LightTextures;
2673 CryCriticalSection FlashTextureSourceSharedRT_AutoUpdate::ms_lock;
2674 int FlashTextureSourceSharedRT_AutoUpdate::ms_lastTickFrameID = 0;
2675 int FlashTextureSourceSharedRT_AutoUpdate::ms_lastTickRTFrameID = 0;
2677 CFlashTextureSourceBase::CFlashPlayerInstanceWrapper::~CFlashPlayerInstanceWrapper()
2679 SAFE_RELEASE(m_pBootStrapper);
2682 std::shared_ptr<IFlashPlayer> CFlashTextureSourceBase::CFlashPlayerInstanceWrapper::GetTempPtr() const
2684 return m_pPlayer;
2687 std::shared_ptr<IFlashPlayer> CFlashTextureSourceBase::CFlashPlayerInstanceWrapper::GetPermPtr(CFlashTextureSourceBase* pSrc)
2689 CryAutoCriticalSection lock(m_lock);
2691 m_canDeactivate = false;
2692 CreateInstance(pSrc);
2694 return m_pPlayer;
2697 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapper::Activate(bool activate, CFlashTextureSourceBase* pSrc)
2699 if (activate)
2701 CryAutoCriticalSection lock(m_lock);
2702 CreateInstance(pSrc);
2704 else if (m_canDeactivate)
2706 m_pPlayer = nullptr;
2710 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapper::CreateInstance(CFlashTextureSourceBase* pSrc)
2712 if (!m_pPlayer && m_pBootStrapper)
2714 m_pPlayer = m_pBootStrapper->CreatePlayerInstance(IFlashPlayer::DEFAULT_NO_MOUSE);
2715 if (m_pPlayer)
2717 #if defined(ENABLE_DYNTEXSRC_PROFILING)
2718 m_pPlayer->LinkDynTextureSource(pSrc);
2719 #endif
2720 m_pPlayer->Advance(0.0f);
2721 m_width = m_pPlayer->GetWidth();
2722 m_height = m_pPlayer->GetHeight();
2727 const char* CFlashTextureSourceBase::CFlashPlayerInstanceWrapper::GetSourceFilePath() const
2729 return m_pBootStrapper ? m_pBootStrapper->GetFilePath() : "UNDEFINED";
2732 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapper::Advance(float delta)
2734 if (m_pPlayer)
2735 m_pPlayer->Advance(delta);
2738 CFlashTextureSourceBase::CFlashPlayerInstanceWrapperLayoutElement::~CFlashPlayerInstanceWrapperLayoutElement()
2740 if (m_pUILayout)
2742 m_pUILayout->Unload();
2744 m_pUILayout = NULL;
2745 m_pPlayer = NULL;
2748 std::shared_ptr<IFlashPlayer> CFlashTextureSourceBase::CFlashPlayerInstanceWrapperLayoutElement::GetTempPtr() const
2750 return m_pPlayer;
2753 std::shared_ptr<IFlashPlayer> CFlashTextureSourceBase::CFlashPlayerInstanceWrapperLayoutElement::GetPermPtr(CFlashTextureSourceBase* pSrc)
2755 CryAutoCriticalSection lock(m_lock);
2757 m_canDeactivate = false;
2758 CreateInstance(pSrc, m_layoutName.c_str());
2760 return m_pPlayer;
2763 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapperLayoutElement::Activate(bool activate, CFlashTextureSourceBase* pSrc)
2765 if (activate)
2767 CryAutoCriticalSection lock(m_lock);
2768 CreateInstance(pSrc, m_layoutName.c_str());
2770 else if (m_canDeactivate)
2772 m_pPlayer = nullptr;
2776 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapperLayoutElement::CreateInstance(CFlashTextureSourceBase* pSrc, const char* layoutName)
2778 UIFramework::IUIFramework* pUIFramework = gEnv->pUIFramework;
2779 if (pUIFramework)
2781 char name[_MAX_PATH];
2782 cry_strcpy(name, layoutName);
2783 PathUtil::RemoveExtension(name);
2784 const char* pExt = PathUtil::GetExt(layoutName);
2785 if (!pExt || strcmpi(pExt, "layout") != 0)
2787 return;
2790 if (pUIFramework->LoadLayout(name) != INVALID_LAYOUT_ID)
2792 m_layoutName = name;
2793 m_pUILayout = pUIFramework->GetLayoutBase(m_layoutName);
2794 if (m_pUILayout)
2796 m_pPlayer = m_pUILayout->GetPlayer();
2798 if (m_pPlayer)
2800 pSrc->m_autoUpdate = !m_pPlayer->HasMetadata("CE_NoAutoUpdate");
2802 #if defined(ENABLE_DYNTEXSRC_PROFILING)
2803 m_pPlayer->LinkDynTextureSource(pSrc);
2804 #endif
2805 m_pPlayer->Advance(0.0f);
2806 m_width = m_pPlayer->GetWidth();
2807 m_height = m_pPlayer->GetHeight();
2814 const char* CFlashTextureSourceBase::CFlashPlayerInstanceWrapperLayoutElement::GetSourceFilePath() const
2816 return m_pPlayer ? m_pPlayer->GetFilePath() : "UNDEFINED";
2819 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapperLayoutElement::Advance(float delta)
2821 if (m_pPlayer)
2822 m_pPlayer->Advance(delta);
2825 CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::~CFlashPlayerInstanceWrapperUIElement()
2827 SAFE_RELEASE(m_pUIElement);
2830 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::SetUIElement(IUIElement* p)
2832 assert(!m_pUIElement);
2833 m_pUIElement = p;
2834 m_pUIElement->AddRef();
2837 std::shared_ptr<IFlashPlayer> CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::GetTempPtr() const
2839 return m_pPlayer;
2842 std::shared_ptr<IFlashPlayer> CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::GetPermPtr(CFlashTextureSourceBase* pSrc)
2844 CryAutoCriticalSection lock(m_lock);
2846 m_canDeactivate = false;
2847 m_activated = true;
2848 UpdateUIElementPlayer(pSrc);
2850 return m_pPlayer;
2853 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::Activate(bool activate, CFlashTextureSourceBase* pSrc)
2855 CryAutoCriticalSection lock(m_lock);
2857 m_activated = m_canDeactivate ? activate : m_activated;
2858 UpdateUIElementPlayer(pSrc);
2861 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::Clear(CFlashTextureSourceBase* pSrc)
2863 CryAutoCriticalSection lock(m_lock);
2865 if (m_pUIElement && m_pPlayer)
2866 m_pUIElement->RemoveTexture(pSrc);
2868 m_pPlayer = nullptr;
2871 const char* CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::GetSourceFilePath() const
2873 return m_pUIElement ? m_pUIElement->GetFlashFile() : "UNDEFINED";
2876 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::UpdatePlayer(CFlashTextureSourceBase* pSrc)
2878 CryAutoCriticalSection lock(m_lock);
2880 UpdateUIElementPlayer(pSrc);
2883 void CFlashTextureSourceBase::CFlashPlayerInstanceWrapperUIElement::UpdateUIElementPlayer(CFlashTextureSourceBase* pSrc)
2885 CRY_ASSERT(gRenDev->m_pRT->IsMainThread() || gRenDev->m_pRT->IsLevelLoadingThread());
2887 if (m_pUIElement)
2889 if (m_activated)
2891 const bool isVisible = m_pUIElement->IsVisible();
2892 std::shared_ptr<IFlashPlayer> pPlayer = isVisible ? m_pUIElement->GetFlashPlayer() : NULL;
2893 if (pPlayer != m_pPlayer)
2895 const bool addTex = m_pPlayer == nullptr;
2896 m_pPlayer = nullptr;
2897 if (isVisible)
2898 m_pPlayer = pPlayer;
2900 if (m_pPlayer)
2902 m_width = m_pPlayer->GetWidth();
2903 m_height = m_pPlayer->GetHeight();
2904 if (addTex)
2905 m_pUIElement->AddTexture(pSrc);
2907 else
2908 m_pUIElement->RemoveTexture(pSrc);
2911 else
2913 if (m_pPlayer)
2914 m_pUIElement->RemoveTexture(pSrc);
2915 m_pPlayer = nullptr;
2920 CFlashTextureSourceBase::CFlashTextureSourceBase(const char* pFlashFileName, const IRenderer::SLoadShaderItemArgs* pArgs)
2921 : m_refCount(1)
2922 , m_lastVisible()
2923 , m_lastVisibleFrameID(0)
2924 , m_width(16)
2925 , m_height(16)
2926 , m_aspectRatio(1.0f)
2927 , m_autoUpdate(true)
2928 , m_perFrameRendering(false)
2929 , m_pFlashFileName(pFlashFileName)
2930 , m_pFlashPlayer(CFlashPlayerInstanceWrapperNULL::Get())
2931 , m_pElement(NULL)
2932 //, m_texStateIDs
2933 #if defined(ENABLE_DYNTEXSRC_PROFILING)
2934 , m_pMatSrc(pArgs ? pArgs->m_pMtlSrc : 0)
2935 , m_pMatSrcParent(pArgs ? pArgs->m_pMtlSrcParent : 0)
2936 #endif
2938 bool valid = false;
2940 if (pFlashFileName)
2942 if (IsFlashUIFile(pFlashFileName))
2944 valid = CreateTexFromFlashFile(pFlashFileName);
2945 if (valid)
2947 gEnv->pFlashUI->RegisterModule(this, pFlashFileName);
2949 else
2951 #ifndef _RELEASE
2952 std::pair<IUIElement*, IUIElement*> result = gEnv->pFlashUI->GetUIElementsByInstanceStr(pFlashFileName);
2953 std::pair<string, int> identifiers = gEnv->pFlashUI->GetUIIdentifiersByInstanceStr(pFlashFileName);
2955 if (!result.first)
2956 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_WARNING,
2957 "UI-Element identifier \"%s\" can't be found in the UI-Database.\n", identifiers.first.c_str());
2958 else if (!result.second)
2959 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_WARNING,
2960 "UI-Element \"%s\" doesn't have an instance %d.\n", identifiers.first.c_str(), identifiers.second);
2961 #endif
2964 else if (IsFlashUILayoutFile(pFlashFileName))
2966 if (m_pFlashPlayer)
2967 m_pFlashPlayer->Clear(this);
2969 m_pFlashPlayer = nullptr;
2971 CFlashPlayerInstanceWrapperLayoutElement* pInstanceWrapper = new CFlashPlayerInstanceWrapperLayoutElement();
2972 pInstanceWrapper->CreateInstance(this, pFlashFileName);
2973 m_pFlashPlayer = pInstanceWrapper;
2974 valid = true;
2976 else
2978 IFlashPlayerBootStrapper* pBootStrapper = gEnv->pScaleformHelper ? gEnv->pScaleformHelper->CreateFlashPlayerBootStrapper() : nullptr;
2979 if (pBootStrapper)
2981 if (pBootStrapper->Load(pFlashFileName))
2983 m_autoUpdate = !pBootStrapper->HasMetadata("CE_NoAutoUpdate");
2985 CFlashPlayerInstanceWrapper* pInstanceWrapper = new CFlashPlayerInstanceWrapper();
2986 pInstanceWrapper->SetBootStrapper(pBootStrapper);
2987 pInstanceWrapper->CreateInstance(this);
2988 m_pFlashPlayer = pInstanceWrapper;
2989 valid = true;
2991 else
2993 SAFE_RELEASE(pBootStrapper);
2999 for (size_t i = 0; i < NumCachedTexStateIDs; ++i)
3001 m_texStateIDs[i].original = EDefaultSamplerStates::Unspecified;
3002 m_texStateIDs[i].patched = EDefaultSamplerStates::Unspecified;
3005 if (valid && m_autoUpdate)
3006 FlashTextureSourceSharedRT_AutoUpdate::Add(this);
3009 bool CFlashTextureSourceBase::IsFlashFile(const char* pFlashFileName)
3011 if (pFlashFileName)
3013 const char* pExt = PathUtil::GetExt(pFlashFileName);
3014 const bool bPath = strchr(pFlashFileName, '/') || strchr(pFlashFileName, '\\');
3016 if (pExt)
3018 if (!bPath)
3020 // Pseudo files (no path, looks up flow-node)
3021 return (!stricmp(pExt, "ui"));
3024 // Real files (looks up filesystem)
3025 return (!stricmp(pExt, "layout") || !stricmp(pExt, "gfx") || !stricmp(pExt, "swf") || !stricmp(pExt, "usm"));
3029 return false;
3032 bool CFlashTextureSourceBase::IsFlashUIFile(const char* pFlashFileName)
3034 if (pFlashFileName)
3036 const char* pExt = PathUtil::GetExt(pFlashFileName);
3037 const bool bPath = strchr(pFlashFileName, '/') || strchr(pFlashFileName, '\\');
3039 if (pExt)
3041 if (!bPath)
3043 // Pseudo files (no path, looks up flow-node)
3044 return !stricmp(pExt, "ui");
3049 return false;
3052 bool CFlashTextureSourceBase::IsFlashUILayoutFile(const char* pFlashFileName)
3054 if (pFlashFileName)
3056 const char* pExt = PathUtil::GetExt(pFlashFileName);
3058 if (pExt)
3060 return !stricmp(pExt, "layout");
3064 return false;
3067 bool CFlashTextureSourceBase::DestroyTexOfFlashFile(const char* name)
3069 if (gEnv->pFlashUI)
3071 IUIElement* pElement = gEnv->pFlashUI->GetUIElementByInstanceStr(name);
3072 if (pElement)
3074 pElement->Unload();
3075 pElement->DestroyThis();
3080 return false;
3083 bool CFlashTextureSourceBase::CreateTexFromFlashFile(const char* name)
3085 if (gEnv->pFlashUI)
3087 //delete old one
3088 if (m_pFlashPlayer)
3089 m_pFlashPlayer->Clear(this);
3090 m_pFlashPlayer = nullptr;
3092 m_pElement = gEnv->pFlashUI->GetUIElementByInstanceStr(name);
3093 if (m_pElement)
3095 CFlashPlayerInstanceWrapperUIElement* pInstanceWrapper = new CFlashPlayerInstanceWrapperUIElement();
3096 m_pElement->SetVisible(true);
3097 pInstanceWrapper->SetUIElement(m_pElement);
3098 pInstanceWrapper->Activate(true, this);
3099 m_pFlashPlayer = pInstanceWrapper;
3100 return true;
3104 return false;
3107 CFlashTextureSourceBase::~CFlashTextureSourceBase()
3109 FlashTextureSourceSharedRT_AutoUpdate::Remove(this);
3111 if (m_pElement) // If module registration happened m_pElement is set
3113 gEnv->pFlashUI->UnregisterModule(this);
3116 if (m_pFlashPlayer)
3117 m_pFlashPlayer->Clear(this);
3119 m_pFlashPlayer = nullptr;
3122 void CFlashTextureSourceBase::AddRef()
3124 CryInterlockedIncrement(&m_refCount);
3127 void CFlashTextureSourceBase::Release()
3129 long refCnt = CryInterlockedDecrement(&m_refCount);
3130 if (refCnt <= 0)
3131 delete this;
3134 void CFlashTextureSourceBase::Activate(bool activate)
3136 m_pFlashPlayer->Activate(activate, this);
3139 #if defined(ENABLE_DYNTEXSRC_PROFILING)
3140 string CFlashTextureSourceBase::GetProfileInfo() const
3143 const char* pMtlName = "NULL";
3144 if (m_pMatSrc || m_pMatSrcParent)
3146 if (m_pMatSrcParent)
3148 if (m_pMatSrcParent->GetName())
3149 pMtlName = m_pMatSrcParent->GetName();
3151 else if (m_pMatSrc)
3153 if (m_pMatSrc->GetName())
3154 pMtlName = m_pMatSrc->GetName();
3158 const char* pSubMtlName = "NULL";
3159 if (m_pMatSrcParent)
3161 if (m_pMatSrc)
3163 if (m_pMatSrc->GetName())
3164 pSubMtlName = m_pMatSrc->GetName();
3167 else
3169 pSubMtlName = 0;
3172 CryFixedStringT<128> info;
3173 info.Format("mat: %s%s%s%s", pMtlName, pSubMtlName ? "|sub: " : "", pSubMtlName ? pSubMtlName : "", !m_pFlashPlayer->CanDeactivate() ? "|$4can't be deactivated!$O" : "");
3175 return info.c_str();
3177 #endif
3179 void* CFlashTextureSourceBase::GetSourceTemp(EDynTextureSource type) const
3181 if (m_pFlashPlayer != nullptr && type == DTS_I_FLASHPLAYER)
3183 return m_pFlashPlayer->GetTempPtr().get();
3185 return nullptr;
3188 void* CFlashTextureSourceBase::GetSourcePerm(EDynTextureSource type)
3190 if (m_pFlashPlayer != nullptr && type == DTS_I_FLASHPLAYER)
3192 return m_pFlashPlayer->GetPermPtr(this).get();
3194 return nullptr;
3197 const char* CFlashTextureSourceBase::GetSourceFilePath() const
3199 if (m_pFlashPlayer != nullptr)
3201 return m_pFlashPlayer->GetSourceFilePath();
3203 return nullptr;
3206 void CFlashTextureSourceBase::GetTexGenInfo(float& offsX, float& offsY, float& scaleX, float& scaleY) const
3208 SDynTexture* pDynTexture = GetDynTexture();
3209 assert(pDynTexture);
3210 if (!pDynTexture || !pDynTexture->IsValid())
3212 offsX = 0;
3213 offsY = 0;
3214 scaleX = 1;
3215 scaleY = 1;
3216 return;
3219 ITexture* pSrcTex = pDynTexture->GetTexture();
3220 float invSrcWidth = 1.0f / (float) pSrcTex->GetWidth();
3221 float invSrcHeight = 1.0f / (float) pSrcTex->GetHeight();
3222 offsX = 0;
3223 offsY = 0;
3224 assert(m_width <= pDynTexture->m_nWidth && m_height <= pDynTexture->m_nHeight);
3225 scaleX = m_width * invSrcWidth;
3226 scaleY = m_height * invSrcHeight;
3229 //////////////////////////////////////////////////////////////////////////
3230 CFlashTextureSource::CFlashTextureSource(const char* pFlashFileName, const IRenderer::SLoadShaderItemArgs* pArgs)
3231 : CFlashTextureSourceBase(pFlashFileName, pArgs)
3233 // create render-target with mip-maps
3234 m_pDynTexture = new SDynTexture(GetWidth(), GetHeight(), Clr_Transparent, eTF_R8G8B8A8, eTT_2D, FT_USAGE_RENDERTARGET | FT_STATE_CLAMP | FT_FORCE_MIPS | FT_USAGE_ALLOWREADSRGB, "FlashTextureSourceUniqueRT");
3235 m_pMipMapper = nullptr;
3238 CFlashTextureSource::~CFlashTextureSource()
3240 SAFE_DELETE(m_pMipMapper);
3241 SAFE_DELETE(m_pDynTexture);
3244 int CFlashTextureSource::GetWidth() const
3246 IFlashPlayerInstanceWrapper* pFlash = GetFlashPlayerInstanceWrapper();
3247 return pFlash ? max(Align8(pFlash->GetWidth()), 16) : 16;
3250 int CFlashTextureSource::GetHeight() const
3252 IFlashPlayerInstanceWrapper* pFlash = GetFlashPlayerInstanceWrapper();
3253 return pFlash ? max(Align8(pFlash->GetHeight()), 16) : 16;
3256 bool CFlashTextureSource::UpdateDynTex(int rtWidth, int rtHeight)
3258 bool needResize = rtWidth != m_pDynTexture->m_nWidth || rtHeight != m_pDynTexture->m_nHeight || !m_pDynTexture->IsValid();
3259 if (needResize)
3261 if (!m_pDynTexture->Update(rtWidth, rtHeight))
3262 return false;
3264 return true;
3267 //////////////////////////////////////////////////////////////////////////
3268 SDynTexture* CFlashTextureSourceSharedRT::ms_pDynTexture = nullptr;
3269 CMipmapGenPass* CFlashTextureSourceSharedRT::ms_pMipMapper = nullptr;
3270 int CFlashTextureSourceSharedRT::ms_instCount = 0;
3271 uint16 CFlashTextureSourceSharedRT::ms_sharedRTWidth = 256;
3272 uint16 CFlashTextureSourceSharedRT::ms_sharedRTHeight = 256;
3274 CFlashTextureSourceSharedRT::CFlashTextureSourceSharedRT(const char* pFlashFileName, const IRenderer::SLoadShaderItemArgs* pArgs)
3275 : CFlashTextureSourceBase(pFlashFileName, pArgs)
3277 ++ms_instCount;
3278 if (!ms_pDynTexture)
3280 // create render-target with mip-maps
3281 ms_pDynTexture = new SDynTexture(ms_sharedRTWidth, ms_sharedRTHeight, Clr_Transparent, eTF_R8G8B8A8, eTT_2D, FT_USAGE_RENDERTARGET | FT_STATE_CLAMP | FT_FORCE_MIPS | FT_USAGE_ALLOWREADSRGB, "FlashTextureSourceSharedRT");
3282 ms_pMipMapper = nullptr;
3286 CFlashTextureSourceSharedRT::~CFlashTextureSourceSharedRT()
3288 --ms_instCount;
3289 if (ms_instCount <= 0)
3291 SAFE_DELETE(ms_pMipMapper);
3292 SAFE_DELETE(ms_pDynTexture);
3296 int CFlashTextureSourceSharedRT::GetSharedRTWidth()
3298 return CRenderer::CV_r_DynTexSourceSharedRTWidth > 0 ? Align8(max(CRenderer::CV_r_DynTexSourceSharedRTWidth, 16)) : ms_sharedRTWidth;
3301 int CFlashTextureSourceSharedRT::GetSharedRTHeight()
3303 return CRenderer::CV_r_DynTexSourceSharedRTHeight > 0 ? Align8(max(CRenderer::CV_r_DynTexSourceSharedRTHeight, 16)) : ms_sharedRTHeight;
3306 int CFlashTextureSourceSharedRT::NearestPowerOfTwo(int n)
3308 int k = n;
3309 k--;
3310 k |= k >> 1;
3311 k |= k >> 2;
3312 k |= k >> 4;
3313 k |= k >> 8;
3314 k |= k >> 16;
3315 k++;
3316 return (k - n) <= (n - (k >> 1)) ? k : (k >> 1);
3319 void CFlashTextureSourceSharedRT::SetSharedRTDim(int width, int height)
3321 ms_sharedRTWidth = NearestPowerOfTwo(width > 16 ? width : 16);
3322 ms_sharedRTHeight = NearestPowerOfTwo(height > 16 ? height : 16);
3325 void CFlashTextureSourceSharedRT::SetupSharedRenderTargetRT()
3327 if (ms_pDynTexture)
3329 const int rtWidth = GetSharedRTWidth();
3330 const int rtHeight = GetSharedRTHeight();
3331 bool needResize = rtWidth != ms_pDynTexture->m_nWidth || rtHeight != ms_pDynTexture->m_nHeight;
3332 if (!ms_pDynTexture->IsValid() || needResize)
3334 ms_pDynTexture->Update(rtWidth, rtHeight);
3335 ms_pDynTexture->SetUpdateMask();
3337 CTexture* pTex = (CTexture*) ms_pDynTexture->GetTexture();
3338 // prevent leak, this code is only needed on D3D11 to force texture creating
3339 if (pTex)
3340 pTex->GetSurface(-1, 0);
3341 ProbeDepthStencilSurfaceCreation(rtWidth, rtHeight);
3346 //////////////////////////////////////////////////////////////////////////
3347 CDynTextureSourceLayerActivator::PerLayerDynSrcMtls CDynTextureSourceLayerActivator::s_perLayerDynSrcMtls;
3349 void CDynTextureSourceLayerActivator::LoadLevelInfo()
3351 ReleaseData();
3353 const char* pLevelPath = iSystem->GetI3DEngine()->GetLevelFilePath("dyntexsrclayeract.xml");
3355 XmlNodeRef root = iSystem->LoadXmlFromFile(pLevelPath);
3356 if (root)
3358 const int numLayers = root->getChildCount();
3359 for (int curLayer = 0; curLayer < numLayers; ++curLayer)
3361 XmlNodeRef layer = root->getChild(curLayer);
3362 if (layer)
3364 const char* pLayerName = layer->getAttr("Name");
3365 if (pLayerName)
3367 const int numMtls = layer->getChildCount();
3369 std::vector<string> mtls;
3370 mtls.reserve(numMtls);
3372 for (int curMtl = 0; curMtl < numMtls; ++curMtl)
3374 XmlNodeRef mtl = layer->getChild(curMtl);
3375 if (mtl)
3377 const char* pMtlName = mtl->getAttr("Name");
3378 if (pMtlName)
3379 mtls.push_back(pMtlName);
3383 s_perLayerDynSrcMtls.insert(PerLayerDynSrcMtls::value_type(pLayerName, mtls));
3390 void CDynTextureSourceLayerActivator::ReleaseData()
3392 stl::reconstruct(s_perLayerDynSrcMtls);
3395 void CDynTextureSourceLayerActivator::ActivateLayer(const char* pLayerName, bool activate)
3397 PerLayerDynSrcMtls::const_iterator it = pLayerName ? s_perLayerDynSrcMtls.find(pLayerName) : s_perLayerDynSrcMtls.end();
3398 if (it != s_perLayerDynSrcMtls.end())
3400 const std::vector<string>& mtls = (*it).second;
3401 const size_t numMtls = mtls.size();
3403 const IMaterialManager* pMatMan = gEnv->p3DEngine->GetMaterialManager();
3405 for (size_t i = 0; i < numMtls; ++i)
3407 const char* pMtlName = mtls[i].c_str();
3408 IMaterial* pMtl = pMatMan->FindMaterial(pMtlName);
3409 if (pMtl)
3411 pMtl->ActivateDynamicTextureSources(activate);
3417 //////////////////////////////////////////////////////////////////////////
3418 void CRenderer::EF_AddRTStat(CTexture* pTex, int nFlags, int nW, int nH)
3420 SRTargetStat TS;
3421 uint32 nSize;
3422 ETEX_Format eTF;
3423 if (!pTex)
3425 eTF = eTF_R8G8B8A8;
3426 if (nW < 0)
3427 nW = CRendererResources::s_renderWidth;
3428 if (nH < 0)
3429 nH = CRendererResources::s_renderHeight;
3430 nSize = CTexture::TextureDataSize(nW, nH, 1, 1, 1, eTF, eTM_Optimal);
3431 TS.m_Name = "Back buffer";
3433 else
3435 eTF = pTex->GetDstFormat();
3436 if (nW < 0)
3437 nW = pTex->GetWidth();
3438 if (nH < 0)
3439 nH = pTex->GetHeight();
3440 nSize = CTexture::TextureDataSize(nW, nH, 1, pTex->GetNumMips(), 1, eTF, eTM_Optimal);
3441 const char* szName = pTex->GetName();
3442 if (szName && szName[0] == '$')
3443 TS.m_Name = string("@") + string(&szName[1]);
3444 else
3445 TS.m_Name = szName;
3447 TS.m_eTF = eTF;
3449 if (nFlags > 0)
3451 if (nFlags == 1)
3452 TS.m_Name += " (Target)";
3453 else if (nFlags == 2)
3455 TS.m_Name += " (Depth)";
3456 nSize = nW * nH * 3;
3458 else if (nFlags == 4)
3460 TS.m_Name += " (Stencil)";
3461 nSize = nW * nH;
3463 else if (nFlags == 3)
3465 TS.m_Name += " (Target + Depth)";
3466 nSize += nW * nH * 3;
3468 else if (nFlags == 6)
3470 TS.m_Name += " (Depth + Stencil)";
3471 nSize = nW * nH * 4;
3473 else if (nFlags == 5)
3475 TS.m_Name += " (Target + Stencil)";
3476 nSize += nW * nH;
3478 else if (nFlags == 7)
3480 TS.m_Name += " (Target + Depth + Stencil)";
3481 nSize += nW * nH * 4;
3483 else
3485 assert(0);
3488 TS.m_nSize = nSize;
3489 TS.m_nWidth = nW;
3490 TS.m_nHeight = nH;
3492 m_renderTargetStats.push_back(TS);
3495 void CRenderer::EF_PrintRTStats(const char* szName)
3497 const int nYstep = 14;
3498 int nY = 30; // initial Y pos
3499 int nX = 20; // initial X pos
3500 ColorF col = Col_Green;
3501 IRenderAuxText::Draw2dLabel((float)nX, (float)nY, 1.6f, &col.r, false, "%s", szName);
3502 nX += 10;
3503 nY += 25;
3505 col = Col_White;
3506 int nYstart = nY;
3507 int nSize = 0;
3508 for (size_t i = 0; i < m_renderTargetStats.size(); i++)
3510 SRTargetStat* pRT = &m_renderTargetStats[i];
3512 IRenderAuxText::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);
3513 nY += nYstep;
3514 if (nY >= CRendererResources::s_displayHeight - 25)
3516 nY = nYstart;
3517 nX += 500;
3519 nSize += pRT->m_nSize;
3521 col = Col_Yellow;
3522 IRenderAuxText::Draw2dLabel((float)nX, (float)(nY + 10), 1.4f, &col.r, false, "Total: %d RT's, Size: %.3f Mb", m_renderTargetStats.size(), nSize / 1024.0f / 1024.0f);
3525 STexPool::~STexPool()
3527 #ifndef _RELEASE
3528 bool poolEmpty = true;
3529 #endif
3531 STexPoolItemHdr* pITH = m_ItemsList.m_Next;
3532 while (pITH != &m_ItemsList)
3534 STexPoolItemHdr* pNext = pITH->m_Next;
3535 STexPoolItem* pIT = static_cast<STexPoolItem*>(pITH);
3537 assert(pIT->m_pOwner == this);
3538 #ifndef _RELEASE
3539 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);
3540 poolEmpty = false;
3541 #else
3542 if (pIT->m_pTex)
3544 pIT->m_pTex->ReleaseDeviceTexture(true); // Try to recover in release
3546 #endif
3547 *const_cast<STexPool**>(&pIT->m_pOwner) = NULL;
3548 pITH = pNext;
3550 CRY_ASSERT(poolEmpty, "Texture pool was not empty on shutdown");
3553 const ETEX_Type CTexture::GetTextureType() const
3555 return m_eTT;
3558 const int CTexture::GetTextureID() const
3560 return GetID();
3563 #ifdef TEXTURE_GET_SYSTEM_COPY_SUPPORT
3565 const ColorB* CTexture::GetLowResSystemCopy(uint16& width, uint16& height, int** ppUserData, int maxTexSize)
3567 AUTO_READLOCK(s_LowResSystemCopyLock);
3569 // find slot based on requested texture size, snap texture size to power of 2
3570 int slot = CLAMP((int)log2(maxTexSize) - 4, 0, TEX_SYS_COPY_MAX_SLOTS - 1);
3571 maxTexSize = (int)exp2(slot + 4);
3573 LowResSystemCopyType::iterator it = s_LowResSystemCopy[slot].find(this);
3575 // load if not ready yet
3576 if (it == CTexture::s_LowResSystemCopy[slot].end())
3578 if (m_eTT != eTT_2D || (m_nMips <= 1 && (m_nWidth > maxTexSize || m_nHeight > maxTexSize)) || m_eDstFormat < eTF_BC1 || m_eDstFormat > eTF_BC7)
3579 return nullptr;
3581 // to switch to modify we need to unlock first
3582 s_LowResSystemCopyLock.UnlockRead();
3583 { // to reduce contention, we want to hold the modify lock as shortly as possible
3584 AUTO_MODIFYLOCK(s_LowResSystemCopyLock);
3585 s_LowResSystemCopy[slot][this]; // make a map entry for this
3588 // 'restore' AUTO_READLOCK
3589 s_LowResSystemCopyLock.LockRead();
3590 it = s_LowResSystemCopy[slot].find(this);
3591 SLowResSystemCopy& rCopy = it->second;
3592 PrepareLowResSystemCopy(maxTexSize, rCopy.m_lowResSystemCopy, rCopy.m_nLowResCopyWidth, rCopy.m_nLowResCopyHeight);
3595 if (it != CTexture::s_LowResSystemCopy[slot].end())
3597 width = (*it).second.m_nLowResCopyWidth;
3598 height = (*it).second.m_nLowResCopyHeight;
3599 if (ppUserData)
3600 *ppUserData = &(*it).second.m_nLowResSystemCopyAtlasId;
3601 return (*it).second.m_lowResSystemCopy.GetElements();
3604 assert(!"CTexture::GetLowResSystemCopy failed");
3606 return NULL;
3609 bool CTexture::PrepareLowResSystemCopy(const uint16 maxTexSize, PodArray<ColorB>& textureData, uint16& width, uint16& height)
3611 _smart_ptr<IImageFile> imageData = gEnv->pRenderer->EF_LoadImage(GetName(), 0);
3613 if (imageData)
3615 width = imageData->mfGet_width();
3616 height = imageData->mfGet_height();
3617 byte* pSrcData = imageData->mfGet_image(0);
3618 ETEX_Format texFormat = imageData->mfGetFormat();
3620 int mipLevel = 0;
3622 while (width > maxTexSize || height > maxTexSize)
3624 int sizeDxtMip = gRenDev->GetTextureFormatDataSize(width, height, 1, 1, texFormat, eTM_None);
3625 pSrcData += sizeDxtMip;
3627 width /= 2;
3628 height /= 2;
3629 mipLevel++;
3632 assert(texFormat >= eTF_BC1 && texFormat <= eTF_BC7);
3634 int nSizeDxtMip0 = gRenDev->GetTextureFormatDataSize(width, height, 1, 1, texFormat, eTM_None);
3635 int nSizeMip0 = gRenDev->GetTextureFormatDataSize(width, height, 1, 1, eTF_R8G8B8A8, eTM_None);
3637 textureData.PreAllocate(nSizeMip0 / sizeof(ColorB), nSizeMip0 / sizeof(ColorB));
3639 gRenDev->DXTDecompress(pSrcData, nSizeDxtMip0, (byte*)textureData.GetElements(), width, height, 1, texFormat, false, 4);
3641 if (m_bIsSRGB)
3643 for (int i = 0; i < textureData.Count(); i++)
3645 ColorF colF = textureData[i];
3646 colF.srgb2rgb();
3647 textureData[i] = colF;
3652 return !textureData.IsEmpty();
3655 #endif // TEXTURE_GET_SYSTEM_COPY_SUPPORT