- 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; const char* path;
RefCountedPtr<FTexture> FGameTexture::* pointer; RefCountedPtr<FTexture> FGameTexture::* pointer;
}; };
struct AutoTextureSearchPath2
{
const char* path;
RefCountedPtr<FTexture> FMaterialLayers::* pointer;
};
static AutoTextureSearchPath autosearchpaths[] = static AutoTextureSearchPath autosearchpaths[] =
{ {
{ "brightmaps/", &FGameTexture::Brightmap }, // For backwards compatibility, only for short names { "brightmaps/", &FGameTexture::Brightmap }, // For backwards compatibility, only for short names
{ "materials/brightmaps/", &FGameTexture::Brightmap }, { "materials/brightmaps/", &FGameTexture::Brightmap },
{ "materials/normalmaps/", &FGameTexture::Normal }, };
{ "materials/specular/", &FGameTexture::Specular },
{ "materials/metallic/", &FGameTexture::Metallic }, static AutoTextureSearchPath2 autosearchpaths2[] =
{ "materials/roughness/", &FGameTexture::Roughness }, {
{ "materials/ao/", &FGameTexture::AmbientOcclusion } { "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 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; flags |= GTexf_AutoMaterialsAdded;
} }
@ -283,7 +312,7 @@ bool FGameTexture::ShouldExpandSprite()
expandSprite = false; expandSprite = false;
return 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 // same restriction for the glow map
expandSprite = false; expandSprite = false;

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <memory>
#include "vectors.h" #include "vectors.h"
#include "floatrect.h" #include "floatrect.h"
#include "refcounted.h" #include "refcounted.h"
@ -62,6 +63,18 @@ enum EGameTexFlags
GTexf_NoTrim = 1024, // Don't perform trimming on this texture. 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 // Refactoring helper to allow piece by piece adjustment of the API
class FGameTexture class FGameTexture
{ {
@ -71,14 +84,7 @@ class FGameTexture
// Material layers. These are shared so reference counting is used. // Material layers. These are shared so reference counting is used.
RefCountedPtr<FTexture> Base; RefCountedPtr<FTexture> Base;
RefCountedPtr<FTexture> Brightmap; RefCountedPtr<FTexture> Brightmap;
RefCountedPtr<FTexture> Detailmap; std::unique_ptr<FMaterialLayers> Layers;
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
FString Name; FString Name;
FTextureID id; FTextureID id;
@ -204,14 +210,25 @@ public:
if (lay.Glossiness > -1000) Glossiness = lay.Glossiness; if (lay.Glossiness > -1000) Glossiness = lay.Glossiness;
if (lay.SpecularLevel > -1000) SpecularLevel = lay.SpecularLevel; if (lay.SpecularLevel > -1000) SpecularLevel = lay.SpecularLevel;
if (lay.Brightmap) Brightmap = lay.Brightmap->GetTexture(); if (lay.Brightmap) Brightmap = lay.Brightmap->GetTexture();
if (lay.Normal) Normal = lay.Normal->GetTexture();
if (lay.Specular) Specular = lay.Specular->GetTexture(); bool needlayers = (lay.Normal || lay.Specular || lay.Metallic || lay.Roughness || lay.AmbientOcclusion);
if (lay.Metallic) Metallic = lay.Metallic->GetTexture(); for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES && !needlayers; i++)
if (lay.Roughness) Roughness = lay.Roughness->GetTexture(); {
if (lay.AmbientOcclusion) AmbientOcclusion = lay.AmbientOcclusion->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++) for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++)
{ {
if (lay.CustomShaderTextures[i]) CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture(); if (lay.CustomShaderTextures[i]) Layers->CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture();
}
} }
} }
float GetGlossiness() const { return Glossiness; } float GetGlossiness() const { return Glossiness; }
@ -306,15 +323,22 @@ public:
void GetLayers(TArray<FTexture*>& layers) void GetLayers(TArray<FTexture*>& layers)
{ {
layers.Clear(); 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); if (tex != nullptr) layers.Push(tex);
} }
for (auto& tex : CustomShaderTextures) if (Layers)
{
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()); if (tex != nullptr) layers.Push(tex.get());
} }
} }
}
FVector2 GetDetailScale() const FVector2 GetDetailScale() const
{ {
@ -335,28 +359,34 @@ public:
} }
FTexture* GetGlowmap() FTexture* GetGlowmap()
{ {
return Glowmap.get(); if (!Layers) return nullptr;
return Layers->Glowmap.get();
} }
FTexture* GetDetailmap() FTexture* GetDetailmap()
{ {
return Detailmap.get(); if (!Layers) return nullptr;
return Layers->Detailmap.get();
} }
void SetGlowmap(FTexture *T) void SetGlowmap(FTexture *T)
{ {
Glowmap = T; if (!Layers) Layers = std::make_unique<FMaterialLayers>();
Layers->Glowmap = T;
} }
void SetDetailmap(FTexture* T) void SetDetailmap(FTexture* T)
{ {
Detailmap = T; if (!Layers) Layers = std::make_unique<FMaterialLayers>();
Layers->Detailmap = T;
} }
void SetNormalmap(FTexture* T) void SetNormalmap(FTexture* T)
{ {
Normal = T; if (!Layers) Layers = std::make_unique<FMaterialLayers>();
Layers->Normal = T;
} }
void SetSpecularmap(FTexture* 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 mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2
} }
// Note that the material takes no ownership of the texture! // 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 }); mTextureLayers.Push({ texture, 0, -1 });
} }
mShaderIndex = SHADER_Specular; 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 }); mTextureLayers.Push({ texture, 0, -1 });
} }
@ -108,18 +108,18 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
{ {
mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 }); 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; mLayerFlags |= TEXF_Detailmap;
} }
else else
{ {
mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 }); 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; mLayerFlags |= TEXF_Glowmap;
} }
else else
@ -133,9 +133,9 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
if (index >= FIRST_USER_SHADER) if (index >= FIRST_USER_SHADER)
{ {
const UserShaderDesc& usershader = usershaders[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; if (texture == nullptr) continue;
mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable. 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; hash = -1;
} }
TextureHash hasher = { texture, -1, -1, -1, hash }; TextureDescriptor hasher = { texture, -1, -1, -1, hash };
int trans = Textures.Push (hasher); int trans = Textures.Push (hasher);
Translation.Push (trans); Translation.Push (trans);
if (bucket >= 0) HashFirst[bucket] = 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); uint32_t langid = MAKE_ID(lang[0], lang[1], lang[2], 0);
uint64_t comboid = (uint64_t(langid) << 32) | origTex.GetIndex(); uint64_t comboid = (uint64_t(langid) << 32) | origTex.GetIndex();
LocalizedTextures.Insert(comboid, tex.GetIndex()); LocalizedTextures.Insert(comboid, tex.GetIndex());
Textures[origTex.GetIndex()].HasLocalization = true; Textures[origTex.GetIndex()].Flags |= TEXFLAG_HASLOCALIZATION;
} }
else else
{ {

View file

@ -29,7 +29,7 @@ private:
{ {
if ((unsigned)texnum >= Textures.Size()) return -1; if ((unsigned)texnum >= Textures.Size()) return -1;
if (animate) texnum = Translation[texnum]; 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; return texnum;
} }
@ -183,17 +183,22 @@ private:
// Switches // Switches
struct TextureHash struct TextureDescriptor
{ {
FGameTexture* Texture; FGameTexture* Texture;
int Paletted; // redirection to paletted variant int Paletted; // redirection to paletted variant
int FrontSkyLayer; // and front sky layer, int FrontSkyLayer; // and front sky layer,
int RawTexture; int RawTexture;
int HashNext; 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 }; enum { HASH_END = -1, HASH_SIZE = 1027 };
TArray<TextureHash> Textures; TArray<TextureDescriptor> Textures;
TMap<uint64_t, int> LocalizedTextures; TMap<uint64_t, int> LocalizedTextures;
int HashFirst[HASH_SIZE]; int HashFirst[HASH_SIZE];
FTextureID DefaultTexture; FTextureID DefaultTexture;