Configurable sampling per custom texture in material shaders

This commit is contained in:
RaveYard 2023-08-25 08:23:24 +02:00 committed by Christoph Oelckers
parent 494ec1b3f9
commit 5e24582c3c
9 changed files with 117 additions and 27 deletions

View file

@ -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);
}
//==========================================================================

View file

@ -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)

View file

@ -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<VulkanSampler> ShadowmapSampler;
std::unique_ptr<VulkanSampler> LightmapSampler;
@ -30,5 +37,6 @@ private:
VulkanRenderDevice* fb = nullptr;
std::array<std::unique_ptr<VulkanSampler>, NUMSAMPLERS> mSamplers;
std::array<std::unique_ptr<VulkanSampler>, 2> mOverrideSamplers;
std::array<std::unique_ptr<VulkanSampler>, 4> mPPSamplers;
};

View file

@ -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<VkHardwareTexture*>(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<VkHardwareTexture*>(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<VkHardwareTexture*>(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;
}

View file

@ -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<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
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();
}
}
}
}

View file

@ -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<FWrapperTexture*>(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;

View file

@ -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<MaterialLayerInfo> &GetLayerArray() const

View file

@ -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;
}

View file

@ -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()));