From 10c552fb66a9843cb2b86579430335ddcdd3f9f1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 25 Nov 2022 10:03:04 +0100 Subject: [PATCH] - 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. --- source/common/textures/gametexture.cpp | 41 ++++++++++-- source/common/textures/gametexture.h | 78 ++++++++++++++++------- source/common/textures/hw_material.cpp | 20 +++--- source/common/textures/texturemanager.cpp | 4 +- source/common/textures/texturemanager.h | 13 ++-- 5 files changed, 110 insertions(+), 46 deletions(-) diff --git a/source/common/textures/gametexture.cpp b/source/common/textures/gametexture.cpp index 23b98e8e3..be4063213 100644 --- a/source/common/textures/gametexture.cpp +++ b/source/common/textures/gametexture.cpp @@ -140,16 +140,27 @@ void FGameTexture::AddAutoMaterials() const char* path; RefCountedPtr FGameTexture::* pointer; }; + struct AutoTextureSearchPath2 + { + const char* path; + RefCountedPtr 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(); + 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; diff --git a/source/common/textures/gametexture.h b/source/common/textures/gametexture.h index a9e516ae4..4a1d4d2f3 100644 --- a/source/common/textures/gametexture.h +++ b/source/common/textures/gametexture.h @@ -1,5 +1,6 @@ #pragma once #include +#include #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 Detailmap; + RefCountedPtr Glowmap; + RefCountedPtr Normal; // Normal map texture + RefCountedPtr Specular; // Specular light texture for the diffuse+normal+specular light model + RefCountedPtr Metallic; // Metalness texture for the physically based rendering (PBR) light model + RefCountedPtr Roughness; // Roughness texture for PBR + RefCountedPtr AmbientOcclusion; // Ambient occlusion texture for PBR + RefCountedPtr 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 Base; RefCountedPtr Brightmap; - RefCountedPtr Detailmap; - RefCountedPtr Glowmap; - RefCountedPtr Normal; // Normal map texture - RefCountedPtr Specular; // Specular light texture for the diffuse+normal+specular light model - RefCountedPtr Metallic; // Metalness texture for the physically based rendering (PBR) light model - RefCountedPtr Roughness; // Roughness texture for PBR - RefCountedPtr AmbientOcclusion; // Ambient occlusion texture for PBR - RefCountedPtr CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; // Custom texture maps for custom hardware shaders + std::unique_ptr 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(); + + 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& 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(); + Layers->Glowmap = T; } void SetDetailmap(FTexture* T) { - Detailmap = T; + if (!Layers) Layers = std::make_unique(); + Layers->Detailmap = T; } void SetNormalmap(FTexture* T) { - Normal = T; + if (!Layers) Layers = std::make_unique(); + Layers->Normal = T; } void SetSpecularmap(FTexture* T) { - Specular = T; + if (!Layers) Layers = std::make_unique(); + Layers->Specular = T; } }; diff --git a/source/common/textures/hw_material.cpp b/source/common/textures/hw_material.cpp index 3abd4fae9..c6b38e5a6 100644 --- a/source/common/textures/hw_material.cpp +++ b/source/common/textures/hw_material.cpp @@ -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. diff --git a/source/common/textures/texturemanager.cpp b/source/common/textures/texturemanager.cpp index ebdfab465..52d0efd02 100644 --- a/source/common/textures/texturemanager.cpp +++ b/source/common/textures/texturemanager.cpp @@ -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 { diff --git a/source/common/textures/texturemanager.h b/source/common/textures/texturemanager.h index 7d9815991..41fe71b6f 100644 --- a/source/common/textures/texturemanager.h +++ b/source/common/textures/texturemanager.h @@ -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 Textures; + TArray Textures; TMap LocalizedTextures; int HashFirst[HASH_SIZE]; FTextureID DefaultTexture;