implement per-map shaders

per-class shaders TODO
This commit is contained in:
Ricardo Luís Vaz Silva 2025-01-09 23:43:42 -03:00 committed by Magnus Norddahl
commit e246639085
12 changed files with 322 additions and 40 deletions

View file

@ -639,6 +639,20 @@ bool FScanner::CheckToken (int token, bool evaluate)
return false;
}
bool FScanner::PeekToken (int token, bool evaluate)
{
if (GetToken (evaluate))
{
if (TokenType == token)
{
UnGet ();
return true;
}
UnGet ();
}
return false;
}
//==========================================================================
//
// FScanner :: GetNumber

View file

@ -114,6 +114,7 @@ public:
void TokenMustBe(int token);
void MustGetToken(int token, bool evaluate = false);
bool CheckToken(int token, bool evaluate = false);
bool PeekToken(int token, bool evaluate = false);
bool CheckTokenId(ENamedName id);
bool GetNumber(bool evaluate = false);

View file

@ -8,10 +8,11 @@ class FMaterial;
struct FMaterialState
{
FMaterial* mMaterial = nullptr;
int mClampMode;
int mTranslation;
int mOverrideShader;
bool mChanged;
int mClampMode = 0;
int mTranslation = CLAMP_NONE;
int mOverrideShader = -1;
bool mChanged = false;
GlobalShaderAddr globalShaderAddr = {0, 3, 0}; // null global shader entry, TODO
void Reset()
{
@ -20,5 +21,6 @@ struct FMaterialState
mClampMode = CLAMP_NONE;
mOverrideShader = -1;
mChanged = false;
globalShaderAddr = {0, 3, 0};
}
};

View file

@ -541,17 +541,7 @@ public:
}
private:
void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader)
{
mMaterial.mMaterial = mat;
mMaterial.mClampMode = clampmode;
mMaterial.mTranslation = translation;
mMaterial.mOverrideShader = overrideshader;
mMaterial.mChanged = true;
mTextureModeFlags = mat->GetLayerFlags();
auto scale = mat->GetDetailScale();
mSurfaceUniforms.uDetailParms = { scale.X, scale.Y, 2, 0 };
}
void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader);
public:
void SetMaterial(FGameTexture* tex, EUpscaleFlags upscalemask, int scaleflags, int clampmode, int translation, int overrideshader)

View file

@ -328,16 +328,18 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
auto base = Source();
int clampmode = state.mClampMode;
int translation = state.mTranslation;
GlobalShaderAddr globalShaderAddr = state.globalShaderAddr;
auto translationp = IsLuminosityTranslation(translation)? translation : intptr_t(GPalette.GetTranslation(GetTranslationType(translation), GetTranslationIndex(translation)));
clampmode = base->GetClampMode(clampmode);
for (auto& set : mDescriptorSets)
{
if (set.clampmode == clampmode && set.remap == translationp) return set;
if (set.clampmode == clampmode && set.remap == translationp && set.globalShaderAddr == globalShaderAddr) return set;
}
int numLayers = NumLayers();
auto globalshader = GetGlobalShader(globalShaderAddr);
int numLayersMat = *globalshader ? NumNonMaterialLayers() : NumLayers();
auto descriptors = fb->GetDescriptorSetManager();
auto* sampler = fb->GetSamplerManager()->Get(clampmode);
@ -348,12 +350,27 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
if (!(layer->scaleFlags & CTF_Indexed))
{
for (int i = 1; i < numLayers; i++)
for (int i = 1; i < numLayersMat; i++)
{
auto syslayer = static_cast<VkHardwareTexture*>(GetLayer(i, 0, &layer));
auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags);
descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode));
}
if(*globalshader)
{
size_t i = 0;
for (auto& texture : globalshader->CustomShaderTextures)
{
if (texture != nullptr)
{
VkHardwareTexture *tex = static_cast<VkHardwareTexture*>(texture.get()->GetHardwareTexture(0, 0));
VkTextureImage *img = tex->GetImage(texture.get(), 0, 0);
descriptors->AddBindlessTextureIndex(img->View.get(), fb->GetSamplerManager()->Get(globalshader->CustomShaderTextureSampling[i], clampmode));
}
i++;
}
}
}
else
{
@ -363,9 +380,8 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags);
descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode));
}
numLayers = 3;
}
mDescriptorSets.emplace_back(clampmode, translationp, bindlessIndex);
mDescriptorSets.emplace_back(clampmode, translationp, bindlessIndex, globalShaderAddr);
return mDescriptorSets.back();
}

View file

@ -78,12 +78,14 @@ private:
int clampmode;
intptr_t remap;
int bindlessIndex;
GlobalShaderAddr globalShaderAddr;
DescriptorEntry(int cm, intptr_t f, int index)
DescriptorEntry(int cm, intptr_t f, int index, GlobalShaderAddr addr)
{
clampmode = cm;
remap = f;
bindlessIndex = index;
globalShaderAddr = addr;
}
};

View file

@ -656,10 +656,20 @@ void VulkanRenderDevice::DownloadLightmap(int arrayIndex, uint16_t* buffer)
int VulkanRenderDevice::GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation)
{
GlobalShaderAddr addr;
auto globalshader = GetGlobalShader(material->GetShaderIndex(), nullptr, addr);
FMaterialState materialState;
materialState.mMaterial = material;
materialState.mClampMode = clampmode;
materialState.mTranslation = translation;
if(addr.type == 1 && *globalshader)
{ // handle per-map global shaders
materialState.globalShaderAddr = addr;
materialState.mOverrideShader = globalshader->shaderindex;
}
return static_cast<VkMaterial*>(material)->GetBindlessIndex(materialState);
}

View file

@ -94,10 +94,38 @@ struct GlobalShaderDesc
int shaderindex = -1;
RefCountedPtr<FTexture> CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES];
MaterialLayerSampling CustomShaderTextureSampling[MAX_CUSTOM_HW_SHADER_TEXTURES];
operator bool() const { return shaderindex >= 0; }
};
struct GlobalShaderAddr
{
int16_t num; // [0 - NUM_BUILTIN_SHADERS)
int16_t type; // 0 - global, 1 - map, 2 - class, 3 - invalid
int32_t name; // global - unused, 1 - map name index, 2 - class name index
bool operator<(GlobalShaderAddr other)
{
return reinterpret_cast<uint64_t&>(*this) < reinterpret_cast<uint64_t&>(other);
}
bool operator==(GlobalShaderAddr other)
{
return reinterpret_cast<uint64_t&>(*this) == reinterpret_cast<uint64_t&>(other);
}
};
static_assert(sizeof(GlobalShaderAddr) == sizeof(uint64_t));
extern const GlobalShaderDesc nullglobalshader;
extern GlobalShaderDesc globalshaders[NUM_BUILTIN_SHADERS];
const GlobalShaderAddr GetGlobalShaderAddr(int shaderNum, class PClass * curActor); // full checks
const GlobalShaderDesc * GetGlobalShader(int shaderNum, class PClass * curActor, GlobalShaderAddr &addr); // full checks
const GlobalShaderDesc * GetGlobalShader(int shaderNum, class PClass * curActor); // full checks
const GlobalShaderDesc * GetGlobalShader(GlobalShaderAddr index); // no checks, only use with addrs gotten from GetGlobalShaderAddr
void CleanupGlobalShaders();
// Refactoring helper to allow piece by piece adjustment of the API
class FGameTexture
{

View file

@ -28,12 +28,46 @@
#include "texturemanager.h"
#include "c_cvars.h"
#include "v_video.h"
#include "hw_renderstate.h"
CVAR(Bool, gl_customshader, true, 0);
TArray<UserShaderDesc> usershaders;
void FRenderState::SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader)
{
mMaterial.mMaterial = mat;
mMaterial.mClampMode = clampmode;
mMaterial.mTranslation = translation;
if(overrideshader > 0)
{
mMaterial.mOverrideShader = overrideshader;
mMaterial.globalShaderAddr = {0, 3, 0};
}
else
{ // handle per-map global shaders
GlobalShaderAddr addr;
auto globalshader = GetGlobalShader(mat->GetShaderIndex(), nullptr, addr);
if(addr.type == 1 && globalshader->shaderindex >= 0)
{
mMaterial.mOverrideShader = globalshader->shaderindex;
mMaterial.globalShaderAddr = addr;
}
else
{
mMaterial.mOverrideShader = -1;
mMaterial.globalShaderAddr = {0, 3, 0};
}
}
mMaterial.mChanged = true;
mTextureModeFlags = mat->GetLayerFlags();
auto scale = mat->GetDetailScale();
mSurfaceUniforms.uDetailParms = { scale.X, scale.Y, 2, 0 };
}
//===========================================================================
//
// Constructor
@ -120,11 +154,15 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
mTextureLayers.Push({ placeholder->GetTexture(), 0, -1, MaterialLayerSampling::Default });
}
mNumNonMaterialLayers = mTextureLayers.Size();
auto index = tx->GetShaderIndex();
const auto globalshader = mShaderIndex < FIRST_USER_SHADER ? &globalshaders[mShaderIndex] : &nullglobalshader;
if (gl_customshader)
{
if (index >= FIRST_USER_SHADER || (mShaderIndex < FIRST_USER_SHADER && globalshaders[mShaderIndex].shaderindex >= FIRST_USER_SHADER))
if (index >= FIRST_USER_SHADER || globalshader->shaderindex >= FIRST_USER_SHADER)
{
if (index >= FIRST_USER_SHADER && usershaders[index - FIRST_USER_SHADER].shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
@ -136,24 +174,26 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
{
if (texture != nullptr)
{
mTextureLayers.Push({ texture.get(), 0, -1, tx->Layers->CustomShaderTextureSampling[i++]}); // scalability should be user-definable.
mTextureLayers.Push({ texture.get(), 0, -1, tx->Layers->CustomShaderTextureSampling[i]}); // scalability should be user-definable.
}
i++;
}
}
mShaderIndex = index;
}
else if(mShaderIndex < FIRST_USER_SHADER && globalshaders[mShaderIndex].shaderindex >= FIRST_USER_SHADER)
else if(mShaderIndex < FIRST_USER_SHADER && globalshader->shaderindex >= FIRST_USER_SHADER)
{
size_t i = 0;
for (auto& texture : globalshaders[mShaderIndex].CustomShaderTextures)
for (auto& texture : globalshader->CustomShaderTextures)
{
if (texture != nullptr)
{
mTextureLayers.Push({ texture.get(), 0, -1, globalshaders[mShaderIndex].CustomShaderTextureSampling[i++]}); // scalability should be user-definable.
mTextureLayers.Push({ texture.get(), 0, -1, globalshader->CustomShaderTextureSampling[i]}); // scalability should be user-definable.
}
i++;
}
mShaderIndex = globalshaders[mShaderIndex].shaderindex;
mShaderIndex = globalshader->shaderindex;
}
}
}

View file

@ -30,6 +30,8 @@ class FMaterial
int mLayerFlags = 0;
int mScaleFlags;
int mNumNonMaterialLayers = 0;
public:
FGameTexture *sourcetex; // the owning texture.
@ -65,6 +67,11 @@ public:
return mTextureLayers.Size();
}
int NumNonMaterialLayers() const
{
return mNumNonMaterialLayers;
}
IHardwareTexture *GetLayer(int i, int translation, MaterialLayerInfo **pLayer = nullptr) const;
MaterialLayerSampling GetLayerFilter(int index) const

View file

@ -4011,10 +4011,7 @@ void D_Cleanup()
*(afunc->VMPointer) = NULL;
});
for(auto &gshader : globalshaders)
{
gshader = {};
}
CleanupGlobalShaders();
GC::DelSoftRootHead();

View file

@ -59,8 +59,98 @@ void ParseColorization(FScanner& sc);
extern TDeletingArray<FLightDefaults *> LightDefaults;
extern int AttenuationIsSet;
const GlobalShaderDesc nullglobalshader = {};
GlobalShaderDesc globalshaders[NUM_BUILTIN_SHADERS];
TMap<FName, GlobalShaderDesc> mapshaders[NUM_BUILTIN_SHADERS];
TMap<FName, GlobalShaderDesc> classshaders[NUM_BUILTIN_SHADERS];
const GlobalShaderDesc * GetGlobalShader(int shaderNum, PClass * curActor, GlobalShaderAddr &addr)
{
if(shaderNum < NUM_BUILTIN_SHADERS)
{
GlobalShaderDesc * shader;
if(curActor)
{
while(curActor->TypeName != NAME_Actor)
{
shader = classshaders[shaderNum].CheckKey(curActor->TypeName);
if(shader && shader->shaderindex > 0)
{
addr = {int16_t(shaderNum), 2, curActor->TypeName.GetIndex()};
return shader;
}
curActor = curActor->ParentClass;
}
}
FName MapName = level.MapName;
shader = mapshaders[shaderNum].CheckKey(MapName);
if(shader && shader->shaderindex > 0)
{
addr = {int16_t(shaderNum), 1, MapName.GetIndex()};
return shader;
}
addr = {int16_t(shaderNum), 0, 0};
return &globalshaders[shaderNum];
}
else
{
addr = {0, 3, 0};
return &nullglobalshader;
}
}
const GlobalShaderAddr GetGlobalShaderAddr(int shaderNum, PClass * curActor)
{
GlobalShaderAddr addr;
GetGlobalShader(shaderNum, curActor, addr);
return addr;
}
const GlobalShaderDesc * GetGlobalShader(int shaderNum, PClass * curActor)
{
GlobalShaderAddr dummy;
return GetGlobalShader(shaderNum, curActor, dummy);
}
const GlobalShaderDesc * GetGlobalShader(GlobalShaderAddr index)
{
if(index.num > NUM_BUILTIN_SHADERS || index.type > 2) return &nullglobalshader;
if(index.type == 0) return &globalshaders[index.num];
FName name {ENamedName(index.name)};
assert((index.type == 1 && mapshaders[index.num].CheckKey(name)) || (index.type == 2 && classshaders[index.num].CheckKey(name)) || index.type == 3);
if(index.type == 1) return mapshaders[index.num].CheckKey(name);
if(index.type == 2) return classshaders[index.num].CheckKey(name);
}
void CleanupGlobalShaders()
{
for(auto &gshader : globalshaders)
{
gshader = {};
}
for(auto &gshader2 : mapshaders)
{
gshader2.Clear();
}
for(auto &gshader3 : classshaders)
{
gshader3.Clear();
}
}
struct ExtraUniformCVARData
{
bool isPP;
@ -1413,6 +1503,8 @@ class GLDefsParser
TArray<int> globaltargets;
FString str_globaltargets;
TArray<FName> globalshader_maps;
TArray<FName> globalshader_classes;
UserShaderDesc usershader;
TArray<FString> texNameList;
@ -1528,6 +1620,25 @@ class GLDefsParser
{
sc.ScriptMessage("Invalid globalshader target\n", sc.String);
}
if(sc.CheckString("map"))
{
do
{
sc.MustGetString();
globalshader_maps.Push(sc.String);
}
while(!sc.PeekToken('{'));
}
else if(sc.CheckString("class"))
{
do
{
sc.MustGetString();
globalshader_classes.Push(sc.String);
}
while(!sc.PeekToken('{'));
}
}
else
{
@ -1847,17 +1958,43 @@ class GLDefsParser
}
if(is_globalshader)
{
if(fileSystem.GetFileContainer(workingLump) > fileSystem.GetMaxIwadNum())
if(fileSystem.GetFileContainer(workingLump) > fileSystem.GetMaxIwadNum() && globalshader_maps.Size() == 0 && globalshader_classes.Size() == 0)
{
sc.ScriptError("globalshader only supported on iwad");
return;
}
else for(int target : globaltargets)
{
if(globalshaders[target].shaderindex >= 0)
if(globalshader_maps.Size() > 0)
{
sc.ScriptError("globalshader already exists for '%s'", str_globaltargets.GetChars());
return;
for(FName map : globalshader_maps)
{
if(mapshaders[target][map].shaderindex >= 0)
{
sc.ScriptError("globalshader '%s' already exists for map '%s'", str_globaltargets.GetChars(), map.GetChars());
return;
}
}
}
else if(globalshader_classes.Size() > 0)
{
for(FName clazz : globalshader_classes)
{
if(classshaders[target][clazz].shaderindex >= 0)
{
sc.ScriptError("globalshader '%s' already exists for class '%s'", str_globaltargets.GetChars(), clazz.GetChars());
return;
}
}
}
else
{
if(globalshaders[target].shaderindex >= 0)
{
sc.ScriptError("globalshader '%s' already exists", str_globaltargets.GetChars());
return;
}
}
}
@ -1866,7 +2003,7 @@ class GLDefsParser
int lump = fileSystem.CheckNumForFullName(usershader.shader.GetChars());
if (lump == -1)
{
sc.ScriptError("inexistent shader lump '%s' in globalshader '%s'", usershader.shader.GetChars(), str_globaltargets.GetChars());
sc.ScriptError("inexistent shader lump '%s' in global shader '%s'", usershader.shader.GetChars(), str_globaltargets.GetChars());
return;
}
@ -1875,7 +2012,7 @@ class GLDefsParser
int lump = fileSystem.CheckNumForFullName(usershader.vertshader.GetChars());
if (lump == -1)
{
sc.ScriptError("inexistent vertex shader lump '%s' in globalshader '%s'", usershader.vertshader.GetChars(), str_globaltargets.GetChars());
sc.ScriptError("inexistent vertex shader lump '%s' in global shader '%s'", usershader.vertshader.GetChars(), str_globaltargets.GetChars());
return;
}
}
@ -1906,7 +2043,26 @@ class GLDefsParser
usershader.shaderType = MaterialShaderIndex(target);
globalshaders[target].shaderindex = usershaders.Push(usershader) + FIRST_USER_SHADER;
int shaderIndex = usershaders.Push(usershader) + FIRST_USER_SHADER;
if(globalshader_maps.Size() > 0)
{
for(FName map : globalshader_maps)
{
mapshaders[target][map].shaderindex = shaderIndex;
}
}
else if(globalshader_classes.Size() > 0)
{
for(FName clazz : globalshader_classes)
{
classshaders[target][clazz].shaderindex = shaderIndex;
}
}
else
{
globalshaders[target].shaderindex = shaderIndex;
}
if(hasUniforms)
{
@ -1917,8 +2073,27 @@ class GLDefsParser
{
if (mlay.CustomShaderTextures[i])
{
globalshaders[target].CustomShaderTextureSampling[i] = mlay.CustomShaderTextureSampling[i];
globalshaders[target].CustomShaderTextures[i] = mlay.CustomShaderTextures[i]->GetTexture();
if(globalshader_maps.Size() > 0)
{
for(FName map : globalshader_maps)
{
mapshaders[target][map].CustomShaderTextureSampling[i] = mlay.CustomShaderTextureSampling[i];
mapshaders[target][map].CustomShaderTextures[i] = mlay.CustomShaderTextures[i]->GetTexture();
}
}
else if(globalshader_classes.Size() > 0)
{
for(FName clazz : globalshader_classes)
{
classshaders[target][clazz].CustomShaderTextureSampling[i] = mlay.CustomShaderTextureSampling[i];
classshaders[target][clazz].CustomShaderTextures[i] = mlay.CustomShaderTextures[i]->GetTexture();
}
}
else
{
globalshaders[target].CustomShaderTextureSampling[i] = mlay.CustomShaderTextureSampling[i];
globalshaders[target].CustomShaderTextures[i] = mlay.CustomShaderTextures[i]->GetTexture();
}
}
}