/*============================================================================= D3DTexturesStreaming.cpp : Direct3D9 specific texture streaming technology. Copyright (c) 2001 Crytek Studios. All Rights Reserved. Revision history: * Created by Honitch Andrey =============================================================================*/ #include "RenderPCH.h" #include "DriverD3D9.h" //=============================================================================== //#define TEXUSAGE D3DUSAGE_DYNAMIC //#define TEXPOOL D3DPOOL_DEFAULT #define TEXUSAGE 0 #define TEXPOOL D3DPOOL_MANAGED void STexPic::BuildMips() { } void STexPicD3D::BuildMips() { CD3D9Renderer *r = gcpRendD3D; LPDIRECT3DDEVICE9 dv = r->mfGetD3DDevice(); IDirect3DTexture9 *pID3DTexture = NULL; IDirect3DCubeTexture9 *pID3DCubeTexture = NULL; HRESULT h; D3DLOCKED_RECT d3dlr; D3DSURFACE_DESC ddsdDescDest; if (!m_Mips[0]) CreateMips(); if (m_eTT != eTT_Cubemap) { pID3DTexture = (IDirect3DTexture9*)m_RefTex.m_VidTex; for (int i=0; iGetLevelDesc(i, &ddsdDescDest); assert (ddsdDescDest.Width && ddsdDescDest.Height); int size = CD3D9TexMan::TexSize(ddsdDescDest.Width, ddsdDescDest.Height, ddsdDescDest.Format); SAFE_DELETE(m_Mips[0][i]); SMipmap *mp = new SMipmap(ddsdDescDest.Width, ddsdDescDest.Height, size); m_Mips[0][i] = mp; mp->m_bUploaded = true; h = pID3DTexture->LockRect(i, &d3dlr, NULL, 0); cryMemcpy(&mp->DataArray[0], d3dlr.pBits, size); pID3DTexture->UnlockRect(i); } } else { pID3DCubeTexture = (IDirect3DCubeTexture9*)m_RefTex.m_VidTex; for (int n=0; n<6; n++) { for (int i=0; iGetLevelDesc(i, &ddsdDescDest); assert (ddsdDescDest.Width && ddsdDescDest.Height); int size = CD3D9TexMan::TexSize(ddsdDescDest.Width, ddsdDescDest.Height, ddsdDescDest.Format); SAFE_DELETE(m_Mips[n][i]); SMipmap *mp = new SMipmap(ddsdDescDest.Width, ddsdDescDest.Height, size); m_Mips[n][i] = mp; mp->m_bUploaded = true; h = pID3DCubeTexture->LockRect((D3DCUBEMAP_FACES)n, i, &d3dlr, NULL, 0); cryMemcpy(&mp->DataArray[0], d3dlr.pBits, size); pID3DCubeTexture->UnlockRect((D3DCUBEMAP_FACES)n, i); } } } } bool STexPic::UploadMips(int nStartMip, int nEndMip) { return false; } void STexPic::FakeUploadMips(int nStartMip, int nEndMip) { int i; if (CRenderer::CV_r_texturesstreamingonlyvideo) m_LoadedSize = 0; for (i=nStartMip; i<=nEndMip; i++) { int nLod = i-m_nBaseMip; SMipmap *mp = m_Mips[0][i]; if (mp->m_bUploaded) { #ifdef _DEBUG int nI = i+1; while (nI <= nEndMip) { SMipmap *mp = m_Mips[0][nI]; assert (mp && mp->m_bUploaded); nI++; } #endif break; } m_LoadedSize += m_pFileTexMips[i].m_Size; gRenDev->m_TexMan->m_StatsCurTexMem += m_pFileTexMips[i].m_Size; } } bool STexPicD3D::UploadMips(int nStartMip, int nEndMip) { double time0 = 0; ticks(time0); CD3D9Renderer *r = gcpRendD3D; LPDIRECT3DDEVICE9 dv = r->mfGetD3DDevice(); IDirect3DTexture9 *pID3DTexture = NULL; IDirect3DCubeTexture9 *pID3DCubeTexture = NULL; HRESULT h; D3DLOCKED_RECT d3dlr; int i; if (CRenderer::CV_r_texturesstreamingonlyvideo) { if (!AddToPool(nStartMip, m_nMips-nStartMip)) return true; if (!m_pPoolItem) return true; } if (m_eTT != eTT_Cubemap) { pID3DTexture = (IDirect3DTexture9*)m_RefTex.m_VidTex; if (!pID3DTexture) { if( FAILED( h = dv->CreateTexture(m_Width>>m_nBaseMip, m_Height>>m_nBaseMip, m_nMips-m_nBaseMip, TEXUSAGE, (D3DFORMAT)m_DstFormat, TEXPOOL, &pID3DTexture, NULL))) return true; m_RefTex.m_VidTex = pID3DTexture; } int SizeToLoad = 0; if (m_pPoolItem) { for (i=nStartMip; i<=nEndMip; i++) { int nLod = i-nStartMip; SMipmap *mp = m_Mips[0][i]; gRenDev->m_TexMan->m_StatsCurTexMem += m_pFileTexMips[i].m_Size; gRenDev->m_TexMan->m_UpLoadBytes += m_pFileTexMips[i].m_Size; LPDIRECT3DSURFACE9 pDestSurf, pSrcSurf; h = pID3DTexture->GetSurfaceLevel(nLod, &pDestSurf); pSrcSurf = (LPDIRECT3DSURFACE9)m_pPoolItem->m_pOwner->m_SysSurfaces[nLod]; h = pSrcSurf->LockRect(&d3dlr, NULL, 0); #ifdef _DEBUG int nD3DSize; if (m_DstFormat == D3DFMT_DXT1 || m_DstFormat == D3DFMT_DXT3 || m_DstFormat == D3DFMT_DXT5) nD3DSize = (d3dlr.Pitch/4) * ((mp->VSize+3)&~3); else nD3DSize = d3dlr.Pitch * mp->VSize; assert(nD3DSize == m_pFileTexMips[i].m_Size); #endif SizeToLoad += m_pFileTexMips[i].m_Size; // Copy data to system texture cryMemcpy((byte *)d3dlr.pBits, &mp->DataArray[0], m_pFileTexMips[i].m_Size); // Unlock the system texture pSrcSurf->UnlockRect(); h = dv->UpdateSurface(pSrcSurf, 0, pDestSurf, 0); SAFE_RELEASE(pDestSurf); mp->m_bUploaded = true; } } else { pID3DTexture->SetLOD(nStartMip-m_nBaseMip); for (i=nStartMip; i<=nEndMip; i++) { int nLod = i-m_nBaseMip; SMipmap *mp = m_Mips[0][i]; if (mp->m_bUploaded) { #ifdef _DEBUG int nI = i+1; while (nI <= nEndMip) { SMipmap *mp = m_Mips[0][nI]; assert (mp && mp->m_bUploaded); nI++; } #endif break; } m_LoadedSize += m_pFileTexMips[i].m_Size; gRenDev->m_TexMan->m_StatsCurTexMem += m_pFileTexMips[i].m_Size; gRenDev->m_TexMan->m_UpLoadBytes += m_pFileTexMips[i].m_Size; h = pID3DTexture->LockRect(nLod, &d3dlr, NULL, 0); #ifdef _DEBUG int nD3DSize; if (m_DstFormat == D3DFMT_DXT1 || m_DstFormat == D3DFMT_DXT3 || m_DstFormat == D3DFMT_DXT5) nD3DSize = (d3dlr.Pitch/4) * ((mp->VSize+3)&~3); else nD3DSize = d3dlr.Pitch * mp->VSize; assert(nD3DSize == m_pFileTexMips[i].m_Size); #endif SizeToLoad += m_pFileTexMips[i].m_Size; // Copy data to video texture cryMemcpy((byte *)d3dlr.pBits, &mp->DataArray[0], m_pFileTexMips[i].m_Size); // Unlock the video texture pID3DTexture->UnlockRect(nLod); mp->m_bUploaded = true; } } if (gRenDev->m_LogFileStr) gRenDev->LogStrv(SRendItem::m_RecurseLevel, "Uploading mips '%s'. (Side: %d, %d-%d[%d]), Size: %d, Time: %.3f\n", m_SourceName.c_str(), -1, nStartMip, i-1, m_nMips, SizeToLoad, iTimer->GetAsyncCurTime()); } else { pID3DCubeTexture = (IDirect3DCubeTexture9*)m_RefTex.m_VidTex; if (!pID3DCubeTexture) { if( FAILED( h = dv->CreateCubeTexture(m_Width>>m_nBaseMip, m_nMips-m_nBaseMip, TEXUSAGE, (D3DFORMAT)m_DstFormat, TEXPOOL, &pID3DCubeTexture, NULL))) return true; m_RefTex.m_VidTex = pID3DCubeTexture; } if (!m_pPoolItem) pID3DCubeTexture->SetLOD(nStartMip-m_nBaseMip); for (int n=0; n<6; n++) { int SizeToLoad = 0; if (m_pPoolItem) { for (i=nStartMip; i<=nEndMip; i++) { int nLod = i-nStartMip; SMipmap *mp = m_Mips[n][i]; gRenDev->m_TexMan->m_StatsCurTexMem += m_pFileTexMips[i].m_Size; gRenDev->m_TexMan->m_UpLoadBytes += m_pFileTexMips[i].m_Size; LPDIRECT3DSURFACE9 pDestSurf, pSrcSurf; h = pID3DCubeTexture->GetCubeMapSurface((D3DCUBEMAP_FACES)n, nLod, &pDestSurf); pSrcSurf = (LPDIRECT3DSURFACE9)m_pPoolItem->m_pOwner->m_SysSurfaces[nLod]; h = pSrcSurf->LockRect(&d3dlr, NULL, 0); #ifdef _DEBUG int nD3DSize; if (m_DstFormat == D3DFMT_DXT1 || m_DstFormat == D3DFMT_DXT3 || m_DstFormat == D3DFMT_DXT5) nD3DSize = (d3dlr.Pitch/4) * ((mp->VSize+3)&~3); else nD3DSize = d3dlr.Pitch * mp->VSize; assert(nD3DSize == m_pFileTexMips[i].m_Size); #endif SizeToLoad += m_pFileTexMips[i].m_Size; // Copy data to system texture cryMemcpy((byte *)d3dlr.pBits, &mp->DataArray[0], m_pFileTexMips[i].m_Size); // Unlock the system texture pSrcSurf->UnlockRect(); h = dv->UpdateSurface(pSrcSurf, 0, pDestSurf, 0); SAFE_RELEASE(pDestSurf); mp->m_bUploaded = true; } } else { for (i=nStartMip; i<=nEndMip; i++) { int nLod = i-m_nBaseMip; SMipmap *mp = m_Mips[n][i]; if (mp->m_bUploaded) { #ifdef _DEBUG int nI = i+1; while (nI <= nEndMip) { SMipmap *mp = m_Mips[n][nI]; assert (mp && mp->m_bUploaded); nI++; } #endif break; } if (!mp->DataArray.GetSize()) continue; m_LoadedSize += m_pFileTexMips[i].m_Size; gRenDev->m_TexMan->m_StatsCurTexMem += m_pFileTexMips[i].m_Size; gRenDev->m_TexMan->m_UpLoadBytes += m_pFileTexMips[i].m_Size; h = pID3DCubeTexture->LockRect((D3DCUBEMAP_FACES)n, nLod, &d3dlr, NULL, 0); #ifdef _DEBUG int nD3DSize; if (m_DstFormat == D3DFMT_DXT1 || m_DstFormat == D3DFMT_DXT3 || m_DstFormat == D3DFMT_DXT5) nD3DSize = (d3dlr.Pitch/4) * ((mp->VSize+3)&~3); else nD3DSize = d3dlr.Pitch * mp->VSize; assert(nD3DSize == m_pFileTexMips[i].m_Size); #endif SizeToLoad += m_pFileTexMips[i].m_Size; // Copy data to video texture cryMemcpy((byte *)d3dlr.pBits, &mp->DataArray[0], m_pFileTexMips[i].m_Size); // Unlock the video texture pID3DCubeTexture->UnlockRect((D3DCUBEMAP_FACES)n, nLod); mp->m_bUploaded = true; } } if (gRenDev->m_LogFileStr) gRenDev->LogStrv(SRendItem::m_RecurseLevel, "Uploading mips '%s'. (Side: %d, %d-%d[%d]), Size: %d, Time: %.3f\n", m_SourceName.c_str(), n, nStartMip, i-1, m_nMips, SizeToLoad, iTimer->GetAsyncCurTime()); } } unticks(time0); r->m_RP.m_PS.m_fTexUploadTime += (float)(time0*1000.0*g_SecondsPerCycle); return true; } // Just remove item from the texture object and keep Item in Pool list for future use // This function doesn't release API texture void STexPic::RemoveFromPool() { if (!m_pPoolItem) return; STexPoolItem *pIT = m_pPoolItem; m_pPoolItem = NULL; pIT->m_pTex = NULL; pIT->m_fLastTimeUsed = gRenDev->m_RP.m_RealTime; m_LoadedSize = -1; m_RefTex.m_VidTex = NULL; } bool STexPic::AddToPool(int nStartMip, int nMips) { assert (m_Mips && nStartMipmfGetD3DDevice(); IDirect3DTexture9 *pID3DTexture = NULL; HRESULT h; if (m_pPoolItem) { if (m_pPoolItem->m_pOwner->m_nMips == nMips && m_pPoolItem->m_pOwner->m_Width == mp->USize && m_pPoolItem->m_pOwner->m_Height == mp->VSize) return false; STexPoolItem *pIT = m_pPoolItem; RemoveFromPool(); pIT->LinkFree(&gRenDev->m_TexMan->m_FreeTexPoolItems); int nSides = 1; if (m_eTT == eTT_Cubemap) nSides = 6; for (int j=0; jm_bUploaded = false; } } /*IDirect3DBaseTexture9 *pTex = (IDirect3DBaseTexture9*)pIT->m_pAPITexture; SAFE_RELEASE(pTex); pIT->Unlink(); gRenDev->m_TexMan->m_StatsCurTexMem -= pIT->m_pOwner->m_Size; delete pIT;*/ } pPool = gRenDev->m_TexMan->CreatePool(mp->USize, mp->VSize, nMips, m_DstFormat, m_eTT); if (!pPool) return false; // Try to find empty item in the pool STexPoolItem *pIT = pPool->m_ItemsList.m_Next; while (pIT != &pPool->m_ItemsList) { if (!pIT->m_pTex) break; pIT = pIT->m_Next; } if (pIT != &pPool->m_ItemsList) { pIT->UnlinkFree(); gRenDev->m_TexMan->m_StatsCurTexMem -= pPool->m_Size; } else { pIT = new STexPoolItem; pIT->m_pOwner = pPool; pIT->Link(&pPool->m_ItemsList); // Create API texture for the item in DEFAULT pool IDirect3DCubeTexture9 *pID3DCubeTexture = NULL; pID3DTexture = NULL; if (m_eTT != eTT_Cubemap) { if( FAILED( h = dv->CreateTexture(mp->USize, mp->VSize, nMips, TEXUSAGE, (D3DFORMAT)m_DstFormat, D3DPOOL_DEFAULT, &pID3DTexture, NULL))) { assert(0); return false; } pIT->m_pAPITexture = pID3DTexture; } else { if( FAILED( h = dv->CreateCubeTexture(mp->USize, nMips, TEXUSAGE, (D3DFORMAT)m_DstFormat, D3DPOOL_DEFAULT, &pID3DCubeTexture, NULL))) { assert(0); return false; } pIT->m_pAPITexture = pID3DCubeTexture; } } m_LoadedSize = pPool->m_Size; m_pPoolItem = pIT; pIT->m_pTex = this; m_RefTex.m_VidTex = pIT->m_pAPITexture; return true; } STexPool *CTexMan::CreatePool(int nWidth, int nHeight, int nMips, int nFormat, ETexType eTT) { LPDIRECT3DDEVICE9 dv = gcpRendD3D->mfGetD3DDevice(); HRESULT h; int i; IDirect3DTexture9 *pID3DTexture = NULL; STexPool *pPool = NULL; for (i=0; im_nMips == nMips && pPool->m_Width == nWidth && pPool->m_Height == nHeight && pPool->m_Format == nFormat && pPool->m_eTT == eTT) break; } // Create new pool if (i == m_TexPools.Num()) { pPool = new STexPool; pPool->m_eTT = eTT; pPool->m_Format = nFormat; pPool->m_Width = nWidth; pPool->m_Height = nHeight; pPool->m_nMips = nMips; pPool->m_Size = 0; int wdt = nWidth; int hgt = nHeight; for (i=0; im_Size += CD3D9TexMan::TexSize(wdt, hgt, nFormat); wdt >>= 1; hgt >>= 1; } if (eTT == eTT_Cubemap) pPool->m_Size *= 6; if( FAILED( h = dv->CreateTexture(nWidth, nHeight, nMips, TEXUSAGE, (D3DFORMAT)nFormat, D3DPOOL_SYSTEMMEM, &pID3DTexture, NULL))) return NULL; pPool->m_pSysTexture = pID3DTexture; for (i=0; iGetSurfaceLevel(i, &pDestSurf); pPool->m_SysSurfaces.AddElem(pDestSurf); } pPool->m_SysSurfaces.Shrink(); pPool->m_ItemsList.m_Next = &pPool->m_ItemsList; pPool->m_ItemsList.m_Prev = &pPool->m_ItemsList; gRenDev->m_TexMan->m_TexPools.AddElem(pPool); } return pPool; } void CTexMan::CreatePools() { int nMaxTexSize = gcpRendD3D->m_pd3dDevice->GetAvailableTextureMem(); int i = 10; int j, n; while (i) { int wdt = (1<m_TexMan->m_FreeTexPoolItems.m_PrevFree; while (pIT != &gRenDev->m_TexMan->m_FreeTexPoolItems) { assert (!pIT->m_pTex); STexPoolItem *pITNext = pIT->m_PrevFree; IDirect3DBaseTexture9 *pTex = (IDirect3DBaseTexture9*)pIT->m_pAPITexture; SAFE_RELEASE(pTex); pIT->Unlink(); pIT->UnlinkFree(); m_StatsCurTexMem -= pIT->m_pOwner->m_Size; delete pIT; pIT = pITNext; if (m_StatsCurTexMem < CRenderer::CV_r_texturesstreampoolsize*1024*1024) break; } // Second release old texture objects STexPic *pTP = STexPic::m_Root.m_Prev; while (m_StatsCurTexMem >= CRenderer::CV_r_texturesstreampoolsize*1024*1024) { if (pTP == &STexPic::m_Root) { ICVar *var = iConsole->GetCVar("r_TexturesStreamPoolSize"); var->Set(m_StatsCurTexMem/(1024*1024)+30); iLog->Log("WARNING: Texture pool was changed to %d Mb", CRenderer::CV_r_texturesstreampoolsize); return; } STexPic *Next = pTP->m_Prev; if (pTP != pExclude) pTP->Unload(); pTP = Next; } } void STexPic::PrecacheAsynchronously(float fDist, int Flags) { if (gRenDev->m_bDeviceLost) return; // Ignore predicted load if we near to texture thrashing if (m_nCustomMip) return; PROFILE_FRAME(Texture_Precache); if (gRenDev->m_TexMan->m_Streamed & 1) { if (m_Flags2 & (FT2_WASUNLOADED | FT2_PARTIALLYLOADED)) { if (!IsStreamed()) return; //if (!(Flags & FPR_NEEDLIGHT) && m_eTT == eTT_Bumpmap) // return; if (CRenderer::CV_r_logTexStreaming >= 2) gRenDev->LogStrv(SRendItem::m_RecurseLevel, "Precache '%s' (Stream)\n", m_SourceName.c_str()); LoadFromCache(Flags, fDist); } else { if (CRenderer::CV_r_logTexStreaming >= 2) gRenDev->LogStrv(SRendItem::m_RecurseLevel, "Precache '%s' (Skip)\n", m_SourceName.c_str()); } } if (gRenDev->m_TexMan->m_Streamed & 2) { if (CRenderer::CV_r_logTexStreaming >= 2) gRenDev->LogStrv(SRendItem::m_RecurseLevel, "Precache '%s' (Draw)\n", m_SourceName.c_str()); gcpRendD3D->EF_SetState(GS_NOCOLMASK | GS_NODEPTHTEST); Set(); int nOffs; struct_VERTEX_FORMAT_TRP3F_COL4UB_TEX2F *vTri = gcpRendD3D->GetVBPtr2D(3, nOffs); DWORD col = -1; // Define the triangle vTri[0].x = 0; vTri[0].y = 0; vTri[0].z = 1; vTri[0].rhw = 1.0f; vTri[0].color.dcolor = col; vTri[0].st[0] = 0; vTri[0].st[1] = 0; vTri[1].x = 2; vTri[1].y = 0; vTri[1].z = 1; vTri[1].rhw = 1.0f; vTri[1].color.dcolor = col; vTri[1].st[0] = 1; vTri[1].st[1] = 0; vTri[2].x = 2; vTri[2].y = 2; vTri[2].z = 1; vTri[2].rhw = 1.0f; vTri[2].color.dcolor = col; vTri[2].st[0] = 1; vTri[2].st[1] = 1; gcpRendD3D->UnlockVB2D(); gcpRendD3D->m_pd3dDevice->SetStreamSource(0, gcpRendD3D->m_pVB2D, 0, sizeof(struct_VERTEX_FORMAT_TRP3F_COL4UB_TEX2F)); gcpRendD3D->EF_SetVertexDeclaration(0, VERTEX_FORMAT_TRP3F_COL4UB_TEX2F); gcpRendD3D->m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, nOffs, 1); gcpRendD3D->EF_SetState(GS_NODEPTHTEST); } } void CTexMan::CheckTexLimits(STexPic *pExclude) { ValidateTexSize(); if (!m_Streamed) return; // To avoid textures thrashing we will try to predict it using some statistics // and using 3-Phase old textures releasing scheme m_TexSizeHistory[m_nTexSizeHistory & 7] = gRenDev->m_TexMan->m_StatsCurTexMem; m_nTexSizeHistory++; bool bUp = true; int n = m_nTexSizeHistory-8; if (n < 0) n = 0; int nMinTexSize = 0; int nPrev; for (int i=n; i nPrev) nPrev = m_TexSizeHistory[m]; else bUp = false; } } int nPoolSize = CRenderer::CV_r_texturesstreampoolsize*1024*1024; if (nMinTexSize < (int)(nPoolSize*0.8f)) { if (m_nCustomMip > 0) m_nCustomMip--; } else if (nMinTexSize > (int)(nPoolSize*0.98f)) { if (m_nCustomMip < 2) m_nCustomMip++; } if (!m_nPhaseProcessingTextures) m_nPhaseProcessingTextures = 1; // Phase1: delete old freed pool items if (m_nPhaseProcessingTextures == 1) { float fTime = gRenDev->m_RP.m_RealTime; int n = 20; STexPoolItem *pIT = gRenDev->m_TexMan->m_FreeTexPoolItems.m_PrevFree; while (pIT != &gRenDev->m_TexMan->m_FreeTexPoolItems) { assert (!pIT->m_pTex); STexPoolItem *pITNext = pIT->m_PrevFree; if (fTime-pIT->m_fLastTimeUsed > 2.0f) { IDirect3DBaseTexture9 *pTex = (IDirect3DBaseTexture9*)pIT->m_pAPITexture; SAFE_RELEASE(pTex); pIT->Unlink(); pIT->UnlinkFree(); m_StatsCurTexMem -= pIT->m_pOwner->m_Size; nMinTexSize -= pIT->m_pOwner->m_Size; delete pIT; n--; } pIT = pITNext; if (!n || nMinTexSize <= (int)(nPoolSize*0.88f)) break; } if (nMinTexSize <= (int)(nPoolSize*0.88f)) m_nPhaseProcessingTextures = 0; else if (pIT == &gRenDev->m_TexMan->m_FreeTexPoolItems) { m_nProcessedTextureID1 = 0; m_pProcessedTexture1 = NULL; m_nPhaseProcessingTextures = 2; } } // Phase2: unload old textures (which was used at least 2 secs ago) if (m_nPhaseProcessingTextures == 2) { STexPic *tp; if (!m_nProcessedTextureID1 || !(tp=m_Textures[m_nProcessedTextureID1]) || !tp->m_Prev || tp != m_pProcessedTexture1) tp = STexPic::m_Root.m_Prev; int nFrame = gRenDev->GetFrameID(); int nWeight = 0; while (tp != &STexPic::m_Root) { STexPic *Next = tp->m_Prev; if (tp->m_AccessFrame && nFrame-tp->m_AccessFrame > 100 && !(tp->m_Flags & FT_NOSTREAM)) { nWeight += 10; tp->Unload(); } tp = Next; nWeight++; if (nWeight > 100) break; } if (tp == &STexPic::m_Root) m_nPhaseProcessingTextures = 0; else { m_nProcessedTextureID1 = tp->m_Id; m_pProcessedTexture1 = tp; } } { STexPic *tp; if (!m_nProcessedTextureID2 || !(tp=m_Textures[m_nProcessedTextureID2]) || !tp->m_Prev || tp != m_pProcessedTexture2) tp = STexPic::m_Root.m_Prev; else tp = m_Textures[m_nProcessedTextureID2]; int nFrame = gRenDev->GetFrameID(); int nWeight = 0; while (tp != &STexPic::m_Root) { STexPic *Next = tp->m_Prev; if (tp->m_fMinDistance) { if ((tp->m_Width >64 || tp->m_Height > 64) && tp->m_nCustomMip != m_nCustomMip) { nWeight += 5; tp->m_nCustomMip = m_nCustomMip; tp->m_Flags2 |= FT2_NEEDTORELOAD; } } tp = Next; nWeight++; if (nWeight > 100) break; } if (tp == &STexPic::m_Root) { m_nProcessedTextureID2 = 0; m_pProcessedTexture2 = NULL; } else { m_nProcessedTextureID2 = tp->m_Id; m_pProcessedTexture2 = tp; } } if (!(gRenDev->m_TexMan->m_Streamed & 1)) return; if (CRenderer::CV_r_texturesstreampoolsize < 10) CRenderer::CV_r_texturesstreampoolsize = 10; ValidateTexSize(); // Usually we do it in case of textures thrashing if (gRenDev->m_TexMan->m_StatsCurTexMem >= CRenderer::CV_r_texturesstreampoolsize*1024*1024) UnloadOldTextures(pExclude); }