- did a bit of optimization on FGameTexture.

Since all material layers except the brightmaps are relatively rare encounters these were taken out of the main texture object and offloaded to a substructure that is only allocated on demand.
This commit is contained in:
Christoph Oelckers 2022-11-25 10:03:04 +01:00
parent 52e5e2f59a
commit 10c552fb66
5 changed files with 110 additions and 46 deletions

View file

@ -140,16 +140,27 @@ void FGameTexture::AddAutoMaterials()
const char* path;
RefCountedPtr<FTexture> FGameTexture::* pointer;
};
struct AutoTextureSearchPath2
{
const char* path;
RefCountedPtr<FTexture> FMaterialLayers::* pointer;
};
static AutoTextureSearchPath autosearchpaths[] =
{
{ "brightmaps/", &FGameTexture::Brightmap }, // For backwards compatibility, only for short names
{ "materials/brightmaps/", &FGameTexture::Brightmap },
{ "materials/normalmaps/", &FGameTexture::Normal },
{ "materials/specular/", &FGameTexture::Specular },
{ "materials/metallic/", &FGameTexture::Metallic },
{ "materials/roughness/", &FGameTexture::Roughness },
{ "materials/ao/", &FGameTexture::AmbientOcclusion }
};
static AutoTextureSearchPath2 autosearchpaths2[] =
{
{ "materials/detailmaps/", &FMaterialLayers::Detailmap },
{ "materials/glowmaps/", &FMaterialLayers::Glowmap },
{ "materials/normalmaps/", &FMaterialLayers::Normal },
{ "materials/specular/", &FMaterialLayers::Specular },
{ "materials/metallic/", &FMaterialLayers::Metallic },
{ "materials/roughness/", &FMaterialLayers::Roughness },
{ "materials/ao/", &FMaterialLayers::AmbientOcclusion }
};
if (flags & GTexf_AutoMaterialsAdded) return; // do this only once
@ -181,6 +192,24 @@ void FGameTexture::AddAutoMaterials()
}
}
}
for (size_t i = 0; i < countof(autosearchpaths2); i++)
{
auto& layer = autosearchpaths2[i];
if (!this->Layers || this->Layers.get()->*(layer.pointer) == nullptr) // only if no explicit assignment had been done.
{
FStringf lookup("%s%s%s", layer.path, fullname ? "" : "auto/", searchname.GetChars());
auto lump = fileSystem.CheckNumForFullName(lookup, false, ns_global, true);
if (lump != -1)
{
auto bmtex = TexMan.FindGameTexture(fileSystem.GetFileFullName(lump), ETextureType::Any, FTextureManager::TEXMAN_TryAny);
if (bmtex != nullptr)
{
if (this->Layers == nullptr) this->Layers = std::make_unique<FMaterialLayers>();
this->Layers.get()->* (layer.pointer) = bmtex->GetTexture();
}
}
}
}
flags |= GTexf_AutoMaterialsAdded;
}
@ -283,7 +312,7 @@ bool FGameTexture::ShouldExpandSprite()
expandSprite = false;
return false;
}
if (Glowmap != NULL && (Base->GetWidth() != Glowmap->GetWidth() || Base->GetHeight() != Glowmap->GetHeight()))
if (Layers && Layers->Glowmap != NULL && (Base->GetWidth() != Layers->Glowmap->GetWidth() || Base->GetHeight() != Layers->Glowmap->GetHeight()))
{
// same restriction for the glow map
expandSprite = false;

View file

@ -1,5 +1,6 @@
#pragma once
#include <stdint.h>
#include <memory>
#include "vectors.h"
#include "floatrect.h"
#include "refcounted.h"
@ -62,6 +63,18 @@ enum EGameTexFlags
GTexf_NoTrim = 1024, // Don't perform trimming on this texture.
};
struct FMaterialLayers
{
RefCountedPtr<FTexture> Detailmap;
RefCountedPtr<FTexture> Glowmap;
RefCountedPtr<FTexture> Normal; // Normal map texture
RefCountedPtr<FTexture> Specular; // Specular light texture for the diffuse+normal+specular light model
RefCountedPtr<FTexture> Metallic; // Metalness texture for the physically based rendering (PBR) light model
RefCountedPtr<FTexture> Roughness; // Roughness texture for PBR
RefCountedPtr<FTexture> AmbientOcclusion; // Ambient occlusion texture for PBR
RefCountedPtr<FTexture> CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; // Custom texture maps for custom hardware shaders
};
// Refactoring helper to allow piece by piece adjustment of the API
class FGameTexture
{
@ -71,14 +84,7 @@ class FGameTexture
// Material layers. These are shared so reference counting is used.
RefCountedPtr<FTexture> Base;
RefCountedPtr<FTexture> Brightmap;
RefCountedPtr<FTexture> Detailmap;
RefCountedPtr<FTexture> Glowmap;
RefCountedPtr<FTexture> Normal; // Normal map texture
RefCountedPtr<FTexture> Specular; // Specular light texture for the diffuse+normal+specular light model
RefCountedPtr<FTexture> Metallic; // Metalness texture for the physically based rendering (PBR) light model
RefCountedPtr<FTexture> Roughness; // Roughness texture for PBR
RefCountedPtr<FTexture> AmbientOcclusion; // Ambient occlusion texture for PBR
RefCountedPtr<FTexture> CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; // Custom texture maps for custom hardware shaders
std::unique_ptr<FMaterialLayers> Layers;
FString Name;
FTextureID id;
@ -204,14 +210,25 @@ public:
if (lay.Glossiness > -1000) Glossiness = lay.Glossiness;
if (lay.SpecularLevel > -1000) SpecularLevel = lay.SpecularLevel;
if (lay.Brightmap) Brightmap = lay.Brightmap->GetTexture();
if (lay.Normal) Normal = lay.Normal->GetTexture();
if (lay.Specular) Specular = lay.Specular->GetTexture();
if (lay.Metallic) Metallic = lay.Metallic->GetTexture();
if (lay.Roughness) Roughness = lay.Roughness->GetTexture();
if (lay.AmbientOcclusion) AmbientOcclusion = lay.AmbientOcclusion->GetTexture();
for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++)
bool needlayers = (lay.Normal || lay.Specular || lay.Metallic || lay.Roughness || lay.AmbientOcclusion);
for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES && !needlayers; i++)
{
if (lay.CustomShaderTextures[i]) CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture();
if (lay.CustomShaderTextures[i]) needlayers = true;
}
if (needlayers)
{
Layers = std::make_unique<FMaterialLayers>();
if (lay.Normal) Layers->Normal = lay.Normal->GetTexture();
if (lay.Specular) Layers->Specular = lay.Specular->GetTexture();
if (lay.Metallic) Layers->Metallic = lay.Metallic->GetTexture();
if (lay.Roughness) Layers->Roughness = lay.Roughness->GetTexture();
if (lay.AmbientOcclusion) Layers->AmbientOcclusion = lay.AmbientOcclusion->GetTexture();
for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++)
{
if (lay.CustomShaderTextures[i]) Layers->CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture();
}
}
}
float GetGlossiness() const { return Glossiness; }
@ -306,13 +323,20 @@ public:
void GetLayers(TArray<FTexture*>& layers)
{
layers.Clear();
for (auto tex : { Base.get(), Brightmap.get(), Detailmap.get(), Glowmap.get(), Normal.get(), Specular.get(), Metallic.get(), Roughness.get(), AmbientOcclusion.get() })
for (auto tex : { Base.get(), Brightmap.get() })
{
if (tex != nullptr) layers.Push(tex);
}
for (auto& tex : CustomShaderTextures)
if (Layers)
{
if (tex != nullptr) layers.Push(tex.get());
for (auto tex : { Layers->Detailmap.get(), Layers->Glowmap.get(), Layers->Normal.get(), Layers->Specular.get(), Layers->Metallic.get(), Layers->Roughness.get(), Layers->AmbientOcclusion.get() })
{
if (tex != nullptr) layers.Push(tex);
}
for (auto& tex : Layers->CustomShaderTextures)
{
if (tex != nullptr) layers.Push(tex.get());
}
}
}
@ -335,28 +359,34 @@ public:
}
FTexture* GetGlowmap()
{
return Glowmap.get();
if (!Layers) return nullptr;
return Layers->Glowmap.get();
}
FTexture* GetDetailmap()
{
return Detailmap.get();
if (!Layers) return nullptr;
return Layers->Detailmap.get();
}
void SetGlowmap(FTexture *T)
{
Glowmap = T;
if (!Layers) Layers = std::make_unique<FMaterialLayers>();
Layers->Glowmap = T;
}
void SetDetailmap(FTexture* T)
{
Detailmap = T;
if (!Layers) Layers = std::make_unique<FMaterialLayers>();
Layers->Detailmap = T;
}
void SetNormalmap(FTexture* T)
{
Normal = T;
if (!Layers) Layers = std::make_unique<FMaterialLayers>();
Layers->Normal = T;
}
void SetSpecularmap(FTexture* T)
{
Specular = T;
if (!Layers) Layers = std::make_unique<FMaterialLayers>();
Layers->Specular = T;
}
};

View file

@ -79,17 +79,17 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2
}
// Note that the material takes no ownership of the texture!
else if (tx->Normal.get() && tx->Specular.get())
else if (tx->Layers && tx->Layers->Normal.get() && tx->Layers->Specular.get())
{
for (auto &texture : { tx->Normal.get(), tx->Specular.get() })
for (auto &texture : { tx->Layers->Normal.get(), tx->Layers->Specular.get() })
{
mTextureLayers.Push({ texture, 0, -1 });
}
mShaderIndex = SHADER_Specular;
}
else if (tx->Normal.get() && tx->Metallic.get() && tx->Roughness.get() && tx->AmbientOcclusion.get())
else if (tx->Layers && tx->Layers->Normal.get() && tx->Layers->Metallic.get() && tx->Layers->Roughness.get() && tx->Layers->AmbientOcclusion.get())
{
for (auto &texture : { tx->Normal.get(), tx->Metallic.get(), tx->Roughness.get(), tx->AmbientOcclusion.get() })
for (auto &texture : { tx->Layers->Normal.get(), tx->Layers->Metallic.get(), tx->Layers->Roughness.get(), tx->Layers->AmbientOcclusion.get() })
{
mTextureLayers.Push({ texture, 0, -1 });
}
@ -108,18 +108,18 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
{
mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 });
}
if (tx->Detailmap.get())
if (tx->Layers && tx->Layers->Detailmap.get())
{
mTextureLayers.Push({ tx->Detailmap.get(), 0, CLAMP_NONE });
mTextureLayers.Push({ tx->Layers->Detailmap.get(), 0, CLAMP_NONE });
mLayerFlags |= TEXF_Detailmap;
}
else
{
mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 });
}
if (tx->Glowmap.get())
if (tx->Layers && tx->Layers->Glowmap.get())
{
mTextureLayers.Push({ tx->Glowmap.get(), scaleflags, -1 });
mTextureLayers.Push({ tx->Layers->Glowmap.get(), scaleflags, -1 });
mLayerFlags |= TEXF_Glowmap;
}
else
@ -133,9 +133,9 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
if (index >= FIRST_USER_SHADER)
{
const UserShaderDesc& usershader = usershaders[index - FIRST_USER_SHADER];
if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
if (tx->Layers && usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
{
for (auto& texture : tx->CustomShaderTextures)
for (auto& texture : tx->Layers->CustomShaderTextures)
{
if (texture == nullptr) continue;
mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable.

View file

@ -426,7 +426,7 @@ FTextureID FTextureManager::AddGameTexture (FGameTexture *texture, bool addtohas
hash = -1;
}
TextureHash hasher = { texture, -1, -1, -1, hash };
TextureDescriptor hasher = { texture, -1, -1, -1, hash };
int trans = Textures.Push (hasher);
Translation.Push (trans);
if (bucket >= 0) HashFirst[bucket] = trans;
@ -1150,7 +1150,7 @@ void FTextureManager::AddLocalizedVariants()
uint32_t langid = MAKE_ID(lang[0], lang[1], lang[2], 0);
uint64_t comboid = (uint64_t(langid) << 32) | origTex.GetIndex();
LocalizedTextures.Insert(comboid, tex.GetIndex());
Textures[origTex.GetIndex()].HasLocalization = true;
Textures[origTex.GetIndex()].Flags |= TEXFLAG_HASLOCALIZATION;
}
else
{

View file

@ -29,7 +29,7 @@ private:
{
if ((unsigned)texnum >= Textures.Size()) return -1;
if (animate) texnum = Translation[texnum];
if (localize && Textures[texnum].HasLocalization) texnum = ResolveLocalizedTexture(texnum);
if (localize && Textures[texnum].Flags & TEXFLAG_HASLOCALIZATION) texnum = ResolveLocalizedTexture(texnum);
return texnum;
}
@ -183,17 +183,22 @@ private:
// Switches
struct TextureHash
struct TextureDescriptor
{
FGameTexture* Texture;
int Paletted; // redirection to paletted variant
int FrontSkyLayer; // and front sky layer,
int RawTexture;
int HashNext;
bool HasLocalization;
uint64_t Flags;
};
enum : uint64_t
{
TEXFLAG_HASLOCALIZATION = 1,
TEXFLAG_FIRSTUSER = 65536, // this leaves 16 flags to the texture manager and 48 flags to the user
};
enum { HASH_END = -1, HASH_SIZE = 1027 };
TArray<TextureHash> Textures;
TArray<TextureDescriptor> Textures;
TMap<uint64_t, int> LocalizedTextures;
int HashFirst[HASH_SIZE];
FTextureID DefaultTexture;