From 97eaa46b69a19966e1a802b15081bcdf56eff718 Mon Sep 17 00:00:00 2001 From: RaveYard <29225776+MrRaveYard@users.noreply.github.com> Date: Fri, 25 Aug 2023 08:23:24 +0200 Subject: [PATCH] Configurable sampling per custom texture in material shaders --- src/common/2d/wipe.cpp | 2 +- .../rendering/vulkan/samplers/vk_samplers.cpp | 35 ++++++++++++++++--- .../rendering/vulkan/samplers/vk_samplers.h | 10 +++++- .../vulkan/textures/vk_hwtexture.cpp | 8 ++--- src/common/textures/gametexture.h | 18 +++++++++- src/common/textures/hw_material.cpp | 25 +++++++------ src/common/textures/hw_material.h | 11 ++++-- src/r_data/gldefs.cpp | 33 +++++++++++++++++ src/rendering/swrenderer/r_swscene.cpp | 2 +- 9 files changed, 117 insertions(+), 27 deletions(-) diff --git a/src/common/2d/wipe.cpp b/src/common/2d/wipe.cpp index cc57ca29f..ffa84b096 100644 --- a/src/common/2d/wipe.cpp +++ b/src/common/2d/wipe.cpp @@ -361,7 +361,7 @@ void Wiper_Burn::SetTextures(FGameTexture *startscreen, FGameTexture *endscreen) BurnTexture = new FBurnTexture(WIDTH, HEIGHT); auto mat = FMaterial::ValidateTexture(endScreen, false); mat->ClearLayers(); - mat->AddTextureLayer(BurnTexture, false); + mat->AddTextureLayer(BurnTexture, false, MaterialLayerSampling::Default); } //========================================================================== diff --git a/src/common/rendering/vulkan/samplers/vk_samplers.cpp b/src/common/rendering/vulkan/samplers/vk_samplers.cpp index 7d6b061de..5ed7f23bf 100644 --- a/src/common/rendering/vulkan/samplers/vk_samplers.cpp +++ b/src/common/rendering/vulkan/samplers/vk_samplers.cpp @@ -85,7 +85,7 @@ void VkSamplerManager::ResetHWSamplers() void VkSamplerManager::CreateHWSamplers() { - int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter()? 0 : gl_texture_filter; + int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter() ? 0 : gl_texture_filter; for (int i = CLAMP_NONE; i <= CLAMP_XY; i++) { @@ -137,15 +137,40 @@ void VkSamplerManager::CreateHWSamplers() .MaxLod(0.25f) .DebugName("VkSamplerManager.mSamplers") .Create(fb->GetDevice()); + + + mOverrideSamplers[int(MaterialLayerSampling::NearestMipLinear)] = SamplerBuilder() + .MagFilter(VK_FILTER_NEAREST) + .MinFilter(VK_FILTER_LINEAR) + .AddressMode(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT) + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_LINEAR) + .MaxLod(100.0f) + .Anisotropy(gl_texture_filter_anisotropic) + .Create(fb->GetDevice()); + + mOverrideSamplers[int(MaterialLayerSampling::LinearMipLinear)] = SamplerBuilder() + .MagFilter(VK_FILTER_LINEAR) + .MinFilter(VK_FILTER_LINEAR) + .AddressMode(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT) + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_LINEAR) + .MaxLod(100.0f) + .Anisotropy(gl_texture_filter_anisotropic) + .Create(fb->GetDevice()); } void VkSamplerManager::DeleteHWSamplers() { - for (auto& sampler : mSamplers) + auto deleteSamplers = [&](auto& samplers) { - if (sampler) - fb->GetCommands()->DrawDeleteList->Add(std::move(sampler)); - } + for (auto& sampler : samplers) + { + if (sampler) + fb->GetCommands()->DrawDeleteList->Add(std::move(sampler)); + } + }; + + deleteSamplers(mSamplers); + deleteSamplers(mOverrideSamplers); } VulkanSampler* VkSamplerManager::Get(PPFilterMode filter, PPWrapMode wrap) diff --git a/src/common/rendering/vulkan/samplers/vk_samplers.h b/src/common/rendering/vulkan/samplers/vk_samplers.h index a7f9ac68f..1b2eba348 100644 --- a/src/common/rendering/vulkan/samplers/vk_samplers.h +++ b/src/common/rendering/vulkan/samplers/vk_samplers.h @@ -16,9 +16,16 @@ public: void ResetHWSamplers(); - VulkanSampler *Get(int no) const { return mSamplers[no].get(); } VulkanSampler* Get(PPFilterMode filter, PPWrapMode wrap); + inline VulkanSampler* Get(int no) const { return mSamplers[no].get(); } + inline VulkanSampler* Get(MaterialLayerSampling filterOverride, int no) const + { + if (filterOverride == MaterialLayerSampling::Default) + return Get(no); + return mOverrideSamplers[int(filterOverride)].get(); + } + std::unique_ptr ShadowmapSampler; std::unique_ptr LightmapSampler; @@ -30,5 +37,6 @@ private: VulkanRenderDevice* fb = nullptr; std::array, NUMSAMPLERS> mSamplers; + std::array, 2> mOverrideSamplers; std::array, 4> mPPSamplers; }; diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp index ffb9da351..d0bb5d261 100644 --- a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp @@ -350,13 +350,13 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) descriptor->SetDebugName("VkHardwareTexture.mDescriptorSets"); - VulkanSampler* sampler = fb->GetSamplerManager()->Get(clampmode); + auto* sampler = fb->GetSamplerManager()->Get(clampmode); WriteDescriptors update; MaterialLayerInfo *layer; auto systex = static_cast(GetLayer(0, state.mTranslation, &layer)); auto systeximage = systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags); - update.AddCombinedImageSampler(descriptor.get(), 0, systeximage->View.get(), sampler, systeximage->Layout); + update.AddCombinedImageSampler(descriptor.get(), 0, systeximage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(0), clampmode), systeximage->Layout); if (!(layer->scaleFlags & CTF_Indexed)) { @@ -364,7 +364,7 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) { auto syslayer = static_cast(GetLayer(i, 0, &layer)); auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); - update.AddCombinedImageSampler(descriptor.get(), i, syslayerimage->View.get(), sampler, syslayerimage->Layout); + update.AddCombinedImageSampler(descriptor.get(), i, syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode), syslayerimage->Layout); } } else @@ -373,7 +373,7 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) { auto syslayer = static_cast(GetLayer(i, translation, &layer)); auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); - update.AddCombinedImageSampler(descriptor.get(), i, syslayerimage->View.get(), sampler, syslayerimage->Layout); + update.AddCombinedImageSampler(descriptor.get(), i, syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode), syslayerimage->Layout); } numLayers = 3; } diff --git a/src/common/textures/gametexture.h b/src/common/textures/gametexture.h index 3eb3740a9..a63dc1b37 100644 --- a/src/common/textures/gametexture.h +++ b/src/common/textures/gametexture.h @@ -35,6 +35,14 @@ struct SpritePositioningInfo }; +enum class MaterialLayerSampling +{ + Default = -1, + + NearestMipLinear, + LinearMipLinear, +}; + struct MaterialLayers { float Glossiness; @@ -46,6 +54,8 @@ struct MaterialLayers FGameTexture* Roughness; FGameTexture* AmbientOcclusion; FGameTexture* CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; + + MaterialLayerSampling CustomShaderTextureSampling[MAX_CUSTOM_HW_SHADER_TEXTURES]; }; enum EGameTexFlags @@ -74,6 +84,8 @@ struct FMaterialLayers 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 + + MaterialLayerSampling CustomShaderTextureSampling[MAX_CUSTOM_HW_SHADER_TEXTURES]; }; // Refactoring helper to allow piece by piece adjustment of the API @@ -235,7 +247,11 @@ public: 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(); + if (lay.CustomShaderTextures[i]) + { + Layers->CustomShaderTextureSampling[i] = lay.CustomShaderTextureSampling[i]; + Layers->CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture(); + } } } } diff --git a/src/common/textures/hw_material.cpp b/src/common/textures/hw_material.cpp index 2517c098e..bbfe61e16 100644 --- a/src/common/textures/hw_material.cpp +++ b/src/common/textures/hw_material.cpp @@ -52,7 +52,7 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) mShaderIndex = SHADER_Default; sourcetex = tx; auto imgtex = tx->GetTexture(); - mTextureLayers.Push({ imgtex, scaleflags, -1 }); + mTextureLayers.Push({ imgtex, scaleflags, -1, MaterialLayerSampling::Default }); if (tx->GetUseType() == ETextureType::SWCanvas && static_cast(imgtex)->GetColorFormat() == 0) { @@ -83,7 +83,7 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) { for (auto &texture : { tx->Layers->Normal.get(), tx->Layers->Specular.get() }) { - mTextureLayers.Push({ texture, 0, -1 }); + mTextureLayers.Push({ texture, 0, -1, MaterialLayerSampling::Default }); } mShaderIndex = SHADER_Specular; } @@ -91,7 +91,7 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) { 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, MaterialLayerSampling::Default }); } mShaderIndex = SHADER_PBR; } @@ -101,30 +101,30 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) auto placeholder = TexMan.GameByIndex(1); if (tx->Brightmap.get()) { - mTextureLayers.Push({ tx->Brightmap.get(), scaleflags, -1 }); + mTextureLayers.Push({ tx->Brightmap.get(), scaleflags, -1, MaterialLayerSampling::Default }); mLayerFlags |= TEXF_Brightmap; } else { - mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 }); + mTextureLayers.Push({ placeholder->GetTexture(), 0, -1, MaterialLayerSampling::Default }); } if (tx->Layers && tx->Layers->Detailmap.get()) { - mTextureLayers.Push({ tx->Layers->Detailmap.get(), 0, CLAMP_NONE }); + mTextureLayers.Push({ tx->Layers->Detailmap.get(), 0, CLAMP_NONE, MaterialLayerSampling::Default }); mLayerFlags |= TEXF_Detailmap; } else { - mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 }); + mTextureLayers.Push({ placeholder->GetTexture(), 0, -1, MaterialLayerSampling::Default }); } if (tx->Layers && tx->Layers->Glowmap.get()) { - mTextureLayers.Push({ tx->Layers->Glowmap.get(), scaleflags, -1 }); + mTextureLayers.Push({ tx->Layers->Glowmap.get(), scaleflags, -1, MaterialLayerSampling::Default}); mLayerFlags |= TEXF_Glowmap; } else { - mTextureLayers.Push({ placeholder->GetTexture(), 0, -1 }); + mTextureLayers.Push({ placeholder->GetTexture(), 0, -1, MaterialLayerSampling::Default }); } auto index = tx->GetShaderIndex(); @@ -137,10 +137,13 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) { if (tx->Layers) { + size_t index = 0; for (auto& texture : tx->Layers->CustomShaderTextures) { - if (texture == nullptr) continue; - mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable. + if (texture != nullptr) + { + mTextureLayers.Push({ texture.get(), 0, -1, tx->Layers->CustomShaderTextureSampling[index++]}); // scalability should be user-definable. + } } } mShaderIndex = index; diff --git a/src/common/textures/hw_material.h b/src/common/textures/hw_material.h index 20c38b332..e7509bca2 100644 --- a/src/common/textures/hw_material.h +++ b/src/common/textures/hw_material.h @@ -13,6 +13,7 @@ struct MaterialLayerInfo FTexture* layerTexture; int scaleFlags; int clampflags; + MaterialLayerSampling layerFiltering; }; //=========================================================================== @@ -55,9 +56,9 @@ public: mTextureLayers.Resize(1); } - void AddTextureLayer(FTexture *tex, bool allowscale) + void AddTextureLayer(FTexture *tex, bool allowscale, MaterialLayerSampling filter) { - mTextureLayers.Push({ tex, allowscale }); + mTextureLayers.Push({ tex, allowscale, -1, filter }); } int NumLayers() const @@ -66,7 +67,11 @@ public: } IHardwareTexture *GetLayer(int i, int translation, MaterialLayerInfo **pLayer = nullptr) const; - + + MaterialLayerSampling GetLayerFilter(int index) const + { + return mTextureLayers[index].layerFiltering; + } static FMaterial *ValidateTexture(FGameTexture * tex, int scaleflags, bool create = true); const TArray &GetLayerArray() const diff --git a/src/r_data/gldefs.cpp b/src/r_data/gldefs.cpp index 006be2044..5e5616fc2 100644 --- a/src/r_data/gldefs.cpp +++ b/src/r_data/gldefs.cpp @@ -1371,6 +1371,7 @@ class GLDefsParser if (tex) { bool okay = false; + size_t texIndex = 0; for (size_t i = 0; i < countof(mlay.CustomShaderTextures); i++) { if (!mlay.CustomShaderTextures[i]) @@ -1383,6 +1384,7 @@ class GLDefsParser texNameList.Push(textureName); texNameIndex.Push((int)i); + texIndex = i; okay = true; break; } @@ -1391,6 +1393,34 @@ class GLDefsParser { sc.ScriptError("Error: out of texture units in texture '%s'", tex->GetName().GetChars()); } + + if (sc.CheckToken('{')) + { + while (!sc.CheckToken('}')) + { + sc.MustGetString(); + if (sc.Compare("filter")) + { + sc.MustGetString(); + if (sc.Compare("nearest")) + { + mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::NearestMipLinear; + } + else if (sc.Compare("linear")) + { + mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::LinearMipLinear; + } + else if (sc.Compare("default")) + { + mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::Default; + } + else + { + sc.ScriptError("Error: unexpected '%s' when reading filter property in texture '%s'\n", sc.String, tex ? tex->GetName().GetChars() : "(null)"); + } + } + } + } } } else if (sc.Compare("define")) @@ -1758,10 +1788,12 @@ class GLDefsParser } sc.MustGetString(); bool okay = false; + size_t texIndex = 0; for (size_t i = 0; i < countof(mlay.CustomShaderTextures); i++) { if (!mlay.CustomShaderTextures[i]) { + mlay.CustomShaderTextureSampling[texIndex] = MaterialLayerSampling::Default; mlay.CustomShaderTextures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); if (!mlay.CustomShaderTextures[i]) { @@ -1770,6 +1802,7 @@ class GLDefsParser texNameList.Push(textureName); texNameIndex.Push((int)i); + texIndex = i; okay = true; break; } diff --git a/src/rendering/swrenderer/r_swscene.cpp b/src/rendering/swrenderer/r_swscene.cpp index 491370dfc..2125853a0 100644 --- a/src/rendering/swrenderer/r_swscene.cpp +++ b/src/rendering/swrenderer/r_swscene.cpp @@ -102,7 +102,7 @@ sector_t *SWSceneDrawer::RenderView(player_t *player) fbtex.reset(MakeGameTexture(new FWrapperTexture(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor()), nullptr, ETextureType::SWCanvas)); GetSystemTexture()->AllocateBuffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor() ? 4 : 1); auto mat = FMaterial::ValidateTexture(fbtex.get(), false); - mat->AddTextureLayer(PaletteTexture, false); + mat->AddTextureLayer(PaletteTexture, false, MaterialLayerSampling::Default); Canvas.reset(); Canvas.reset(new DCanvas(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor()));