- fixed texture layer management so that each material layer can decide for itself if it wants to allow upscaling.

- rewrote the hardware texture precacher to use the new texture management to properly track the data to delete.
This commit is contained in:
Christoph Oelckers 2020-04-19 10:08:24 +02:00
commit b2281c38e1
20 changed files with 190 additions and 135 deletions

View file

@ -50,7 +50,10 @@ static void PrecacheTexture(FGameTexture *tex, int cache)
{
if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky))
{
FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
int scaleflags = 0;
if (shouldUpscale(tex, UF_Texture)) scaleflags |= CTF_Upscale;
FMaterial * gltex = FMaterial::ValidateTexture(tex, scaleflags);
if (gltex) screen->PrecacheMaterial(gltex, 0);
}
}
@ -62,7 +65,6 @@ static void PrecacheTexture(FGameTexture *tex, int cache)
//===========================================================================
static void PrecacheList(FMaterial *gltex, SpriteHits& translations)
{
//gltex->BaseLayer()->SystemTextures.CleanUnused(translations, gltex->GetScaleFlags()); this needs to be redone.
SpriteHits::Iterator it(translations);
SpriteHits::Pair* pair;
while (it.NextPair(pair)) screen->PrecacheMaterial(gltex, pair->Key);
@ -76,7 +78,10 @@ static void PrecacheList(FMaterial *gltex, SpriteHits& translations)
static void PrecacheSprite(FGameTexture *tex, SpriteHits &hits)
{
FMaterial * gltex = FMaterial::ValidateTexture(tex, true);
int scaleflags = CTF_Expand;
if (shouldUpscale(tex, UF_Sprite)) scaleflags |= CTF_Upscale;
FMaterial * gltex = FMaterial::ValidateTexture(tex, scaleflags);
if (gltex) PrecacheList(gltex, hits);
}
@ -88,26 +93,36 @@ static void PrecacheSprite(FGameTexture *tex, SpriteHits &hits)
void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitlist)
{
SpriteHits *spritelist = new SpriteHits[sprites.Size()];
SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()];
TMap<PClassActor*, bool>::Iterator it(actorhitlist);
TMap<PClassActor*, bool>::Pair *pair;
uint8_t *modellist = new uint8_t[Models.Size()];
memset(modellist, 0, Models.Size());
memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures());
TMap<FTexture*, bool> allTextures;
TArray<FTexture*> layers;
// this isn't done by the main code so it needs to be done here first:
// check skybox textures and mark the separate faces as used
for (int i = 0; i<TexMan.NumTextures(); i++)
// First collect the potential max. texture set
for (unsigned i = 1; i < TexMan.NumTextures(); i++)
{
// HIT_Wall must be checked for MBF-style sky transfers.
auto gametex = TexMan.GameByIndex(i);
if (gametex &&
gametex->GetTexture()->GetImage() && // only image textures are subject to precaching
gametex->GetUseType() != ETextureType::FontChar && // We do not want to delete font characters here as they are very likely to be needed constantly.
gametex->GetUseType() < ETextureType::Special) // Any texture marked as 'special' is also out.
{
gametex->GetLayers(layers);
for (auto layer : layers)
{
allTextures.Insert(layer, true);
layer->CleanPrecacheMarker();
}
}
// Mark the faces of a skybox as used.
// This isn't done by the main code so it needs to be done here.
// MBF sky transfers are being checked by the calling code to add HIT_Sky for them.
if (texhitlist[i] & (FTextureManager::HIT_Sky))
{
auto tex = TexMan.GameByIndex(i);
auto sb = dynamic_cast<FSkyBox*>(tex->GetTexture());
if (sb)
{
for (int i = 0; i<6; i++)
for (int i = 0; i < 6; i++)
{
if (sb->faces[i])
{
@ -119,6 +134,14 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
}
}
SpriteHits *spritelist = new SpriteHits[sprites.Size()];
SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()];
TMap<PClassActor*, bool>::Iterator it(actorhitlist);
TMap<PClassActor*, bool>::Pair *pair;
uint8_t *modellist = new uint8_t[Models.Size()];
memset(modellist, 0, Models.Size());
memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures());
// Check all used actors.
// 1. mark all sprites associated with its states
// 2. mark all model data and skins associated with its states
@ -190,7 +213,7 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
screen->StartPrecaching();
int cnt = TexMan.NumTextures();
// prepare the textures for precaching. First collect all used layer textures so that we know which ones should not be deleted.
// prepare the textures for precaching. First mark all used layer textures so that we know which ones should not be deleted.
for (int i = cnt - 1; i >= 0; i--)
{
auto tex = TexMan.GameByIndex(i);
@ -198,44 +221,46 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
{
if (texhitlist[i] & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky))
{
FMaterial* mat = FMaterial::ValidateTexture(tex, false, false);
int scaleflags = 0;
if (shouldUpscale(tex, UF_Texture)) scaleflags |= CTF_Upscale;
FMaterial* mat = FMaterial::ValidateTexture(tex, scaleflags, true);
if (mat != nullptr)
{
for (auto ftex : mat->GetLayerArray())
for (auto &layer : mat->GetLayerArray())
{
usedTextures.Insert(ftex, true);
if (layer.layerTexture) layer.layerTexture->MarkForPrecache(0, layer.scaleFlags);
}
}
}
if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0)
{
FMaterial *mat = FMaterial::ValidateTexture(tex, true, false);
int scaleflags = CTF_Expand;
if (shouldUpscale(tex, UF_Sprite)) scaleflags |= CTF_Upscale;
FMaterial *mat = FMaterial::ValidateTexture(tex, true, true);
if (mat != nullptr)
{
for (auto ftex : mat->GetLayerArray())
SpriteHits::Iterator it(*spritehitlist[i]);
SpriteHits::Pair* pair;
while (it.NextPair(pair))
{
usedSprites.Insert(ftex, true);
for (auto& layer : mat->GetLayerArray())
{
if (layer.layerTexture) layer.layerTexture->MarkForPrecache(pair->Key, layer.scaleFlags);
}
}
}
}
}
}
// delete unused textures (i.e. those which didn't get referenced by any material in the cache list.
for (int i = cnt - 1; i >= 0; i--)
// delete unused hardware textures (i.e. those which didn't get referenced by any material in the cache list.)
decltype(allTextures)::Iterator ita(allTextures);
decltype(allTextures)::Pair* paira;
while (it.NextPair(pair))
{
auto tex = TexMan.GameByIndex(i);
if (tex != nullptr && tex->GetUseType() != ETextureType::FontChar)
{
// This is rather counterproductive in a system that can share hardware textures between game textures.
// The precacher needs to be redone to account for that. For now, just skip the deletion, for any normal sized map this won't be a problem.
#if 0
if (usedTextures.CheckKey(tex->GetTexture()) == nullptr && usedSprites.CheckKey(tex->GetTexture()) == nullptr)
{
tex->CleanHardwareData();
}
#endif
}
paira->Key->CleanUnused();
}
if (gl_precache)
@ -246,7 +271,7 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
FImageSource::BeginPrecaching();
// cache all used textures
// cache all used images
for (int i = cnt - 1; i >= 0; i--)
{
auto gtex = TexMan.GameByIndex(i);
@ -262,7 +287,7 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
}
}
// Only register untranslated sprites. Translated ones are very unlikely to require data that can be reused.
// Only register untranslated sprite images. Translated ones are very unlikely to require data that can be reused so they can just be created on demand.
if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CheckKey(0))
{
FImageSource::RegisterForPrecache(tex->GetImage(), V_IsTrueColor());