implement custom uniforms for material shaders

This commit is contained in:
Ricardo Luís Vaz Silva 2025-01-08 06:07:29 -03:00 committed by Nash Muhandes
commit ea09ae1461
13 changed files with 406 additions and 299 deletions

View file

@ -1142,7 +1142,7 @@ UniformField UserUniforms::GetField(const FString &name)
return {field.Type, UniformStruct + field.Offset};
}
void UserUniforms::WriteUniforms(UniformStructHolder &Uniforms)
void UserUniforms::WriteUniforms(UniformStructHolder &Uniforms) const
{
Uniforms.Clear();
Uniforms.addr = UniformStruct;

View file

@ -26,6 +26,9 @@ enum class UniformType
Mat4
};
const char* GetTypeStr(UniformType type);
struct UserUniformValue
{
UniformType Type = UniformType::Undefined;
@ -136,7 +139,7 @@ public:
//must only be called once
void LoadUniforms(const TMap<FString, UserUniformValue> &Uniforms);
void WriteUniforms(UniformStructHolder &Data);
void WriteUniforms(UniformStructHolder &Data) const;
int UniformStructSize = 0;

View file

@ -131,7 +131,7 @@ VkVertexFormat *VkRenderPassManager::GetVertexFormat(int index)
return &VertexFormats[index];
}
VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(bool levelmesh)
VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(bool levelmesh, int UserUniformSize)
{
auto &layout = PipelineLayouts[levelmesh];
if (layout)
@ -144,6 +144,12 @@ VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(bool levelmesh)
builder.AddSetLayout(levelmesh ? descriptors->GetLevelMeshLayout() : descriptors->GetRSBufferLayout());
builder.AddSetLayout(descriptors->GetBindlessLayout());
builder.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants));
if(UserUniformSize > 0)
{
builder.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(PushConstants), UserUniformSize);
}
builder.DebugName("VkRenderPassManager.PipelineLayout");
layout = builder.Create(fb->GetDevice());
return layout.get();
@ -273,15 +279,25 @@ VulkanRenderPass *VkRenderPassSetup::GetRenderPass(int clearTargets)
return RenderPasses[clearTargets].get();
}
VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key)
VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms)
{
auto &item = Pipelines[key];
if (!item)
item = CreatePipeline(key);
return item.get();
auto item = Pipelines.find(key);
if (item == Pipelines.end())
{
Uniforms.Clear();
auto pipeline = CreatePipeline(key, Uniforms);
auto ptr = pipeline.get();
Pipelines.insert(std::pair<VkPipelineKey, PipelineData>{key, PipelineData{std::move(pipeline), Uniforms}});
return ptr;
}
else
{
Uniforms = item->second.Uniforms;
return item->second.pipeline.get();
}
}
std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key)
std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms)
{
GraphicsPipelineBuilder builder;
builder.Cache(fb->GetRenderPassManager()->GetCache());
@ -365,10 +381,12 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
builder.RasterizationSamples((VkSampleCountFlagBits)PassKey.Samples);
builder.Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.ShaderKey.UseLevelMesh));
builder.Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.ShaderKey.UseLevelMesh, program->Uniforms.sz));
builder.RenderPass(GetRenderPass(0));
builder.DebugName("VkRenderPassSetup.Pipeline");
Uniforms = program->Uniforms;
return builder.Create(fb->GetDevice());
}

View file

@ -69,21 +69,27 @@ public:
bool operator!=(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) != 0; }
};
struct PipelineData
{
std::unique_ptr<VulkanPipeline> pipeline;
UniformStructHolder Uniforms;
};
class VkRenderPassSetup
{
public:
VkRenderPassSetup(VulkanRenderDevice* fb, const VkRenderPassKey &key);
VulkanRenderPass *GetRenderPass(int clearTargets);
VulkanPipeline *GetPipeline(const VkPipelineKey &key);
VulkanPipeline *GetPipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms);
VkRenderPassKey PassKey;
std::unique_ptr<VulkanRenderPass> RenderPasses[8];
std::map<VkPipelineKey, std::unique_ptr<VulkanPipeline>> Pipelines;
std::map<VkPipelineKey, PipelineData> Pipelines;
private:
std::unique_ptr<VulkanRenderPass> CreateRenderPass(int clearTargets);
std::unique_ptr<VulkanPipeline> CreatePipeline(const VkPipelineKey &key);
std::unique_ptr<VulkanPipeline> CreatePipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms);
VulkanRenderDevice* fb = nullptr;
};
@ -109,7 +115,7 @@ public:
VkRenderPassSetup *GetRenderPass(const VkRenderPassKey &key);
int GetVertexFormat(const std::vector<size_t>& bufferStrides, const std::vector<FVertexBufferAttribute>& attrs);
VkVertexFormat *GetVertexFormat(int index);
VulkanPipelineLayout* GetPipelineLayout(bool levelmesh);
VulkanPipelineLayout* GetPipelineLayout(bool levelmesh, int UserUniformSize);
VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key);

View file

@ -138,14 +138,14 @@ FString VkPPShader::CreateUniformBlockDecl(const char* name, const std::vector<U
decl.Format("layout(%s) uniform %s\n{\n", layout.GetChars(), name);
for (size_t i = 0; i < fields.size(); i++)
{
decl.AppendFormat("\t%s %s;\n", GetTypeStr(fields[i].Type), fields[i].Name);
decl.AppendFormat("\t%s %s;\n", GetTypeStr(fields[i].Type), fields[i].Name.GetChars());
}
decl += "};\n";
return decl;
}
const char* VkPPShader::GetTypeStr(UniformType type)
const char* GetTypeStr(UniformType type)
{
switch (type)
{

View file

@ -25,7 +25,6 @@ public:
private:
FString LoadShaderCode(const FString &lumpname, const FString &defines, int version);
static FString CreateUniformBlockDecl(const char* name, const std::vector<UniformFieldDesc>& fields, int bindingpoint);
static const char* GetTypeStr(UniformType type);
ShaderIncludeResult OnInclude(FString headerName, FString includerName, size_t depth, bool system);
FString LoadPublicShaderLump(const char* lumpname);

View file

@ -113,9 +113,9 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key)
};
const auto& desc = effectshaders[key.SpecialEffect];
program.vert = LoadVertShader(desc.ShaderName, mainvp, vert_nocustom, desc.defines, key);
program.vert = LoadVertShader(desc.ShaderName, mainvp, vert_nocustom, desc.defines, key, nullptr);
if (!key.NoFragmentShader)
program.frag = LoadFragShader(desc.ShaderName, desc.fp1, desc.fp2, desc.fp3, desc.fp4, desc.fp5, desc.defines, key);
program.frag = LoadFragShader(desc.ShaderName, desc.fp1, desc.fp2, desc.fp3, desc.fp4, desc.fp5, desc.defines, key, nullptr);
}
else
{
@ -153,9 +153,9 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key)
if (key.EffectState < FIRST_USER_SHADER)
{
const auto& desc = defaultshaders[key.EffectState];
program.vert = LoadVertShader(desc.ShaderName, mainvp, vert_nocustom, desc.Defines, key);
program.vert = LoadVertShader(desc.ShaderName, mainvp, vert_nocustom, desc.Defines, key, nullptr);
if (!key.NoFragmentShader)
program.frag = LoadFragShader(desc.ShaderName, mainfp, desc.material_lump, desc.mateffect_lump, desc.lightmodel_lump_shared, desc.lightmodel_lump, desc.Defines, key);
program.frag = LoadFragShader(desc.ShaderName, mainfp, desc.material_lump, desc.mateffect_lump, desc.lightmodel_lump_shared, desc.lightmodel_lump, desc.Defines, key, nullptr);
}
else
{
@ -163,15 +163,45 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key)
const FString& name = ExtractFileBase(desc.shader.GetChars());
FString defines = defaultshaders[desc.shaderType].Defines + desc.defines;
program.vert = LoadVertShader(name, mainvp, desc.vertshader.IsEmpty() ? vert_nocustom : desc.vertshader.GetChars(), defines.GetChars(), key);
program.vert = LoadVertShader(name, mainvp, desc.vertshader.IsEmpty() ? vert_nocustom : desc.vertshader.GetChars(), defines.GetChars(), key, &desc.Uniforms);
if (!key.NoFragmentShader)
program.frag = LoadFragShader(name, mainfp, desc.shader.GetChars(), defaultshaders[desc.shaderType].mateffect_lump, defaultshaders[desc.shaderType].lightmodel_lump_shared, defaultshaders[desc.shaderType].lightmodel_lump, defines.GetChars(), key);
program.frag = LoadFragShader(name, mainfp, desc.shader.GetChars(), defaultshaders[desc.shaderType].mateffect_lump, defaultshaders[desc.shaderType].lightmodel_lump_shared, defaultshaders[desc.shaderType].lightmodel_lump, defines.GetChars(), key, &desc.Uniforms);
desc.Uniforms.WriteUniforms(program.Uniforms);
}
}
return &program;
}
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key)
static void addPushConstants(FString &layoutBlock, const UserUniforms *uniforms)
{
layoutBlock << "// This must match the PushConstants struct\n";
layoutBlock << "layout(push_constant) uniform PushConstants\n";
layoutBlock << "{\n";
layoutBlock << "#if defined(USE_LEVELMESH)\n";
layoutBlock << " int unused0;\n";
layoutBlock << " int unused1;\n";
layoutBlock << "#else\n";
layoutBlock << " int uDataIndex; // surfaceuniforms index\n";
layoutBlock << " int uLightIndex; // dynamic lights\n";
layoutBlock << "#endif\n";
layoutBlock << " int uBoneIndexBase; // bone animation\n";
layoutBlock << " int uFogballIndex; // fog balls\n";
if(uniforms && uniforms->UniformStructSize)
{
for(auto &field : uniforms->Fields)
{
//layoutBlock.AppendFormat(" layout(offset = %d) %s %s;\n", (field.Offset + sizeof(PushConstants)), GetTypeStr(field.Type), field.Name.GetChars());
layoutBlock.AppendFormat(" %s %s;\n", GetTypeStr(field.Type), field.Name.GetChars());
}
}
layoutBlock << "};\n";
}
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms)
{
FString definesBlock;
definesBlock << defines;
@ -192,9 +222,11 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername
definesBlock << "#define USE_LEVELMESH\n";
FString layoutBlock;
addPushConstants(layoutBlock, uniforms);
layoutBlock << LoadPrivateShaderLump("shaders/scene/layout_shared.glsl").GetChars() << "\n";
layoutBlock << LoadPrivateShaderLump("shaders/scene/layout_vert.glsl").GetChars() << "\n";
FString codeBlock;
codeBlock << LoadPrivateShaderLump(vert_lump).GetChars() << "\n";
codeBlock << LoadPublicShaderLump(vert_lump_custom).GetChars() << "\n";
@ -211,7 +243,7 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername
.Create(shadername.GetChars(), fb->GetDevice());
}
std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *light_lump_shared, const char *light_lump, const char *defines, const VkShaderKey& key)
std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *light_lump_shared, const char *light_lump, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms)
{
FString definesBlock;
if (fb->IsRayQueryEnabled()) definesBlock << "\n#define SUPPORTS_RAYQUERY\n";
@ -299,9 +331,11 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername
else definesBlock << "#define uFogEnabled 0\n";
FString layoutBlock;
addPushConstants(layoutBlock, uniforms);
layoutBlock << LoadPrivateShaderLump("shaders/scene/layout_shared.glsl").GetChars() << "\n";
layoutBlock << LoadPrivateShaderLump("shaders/scene/layout_frag.glsl").GetChars() << "\n";
FString codeBlock;
codeBlock << LoadPrivateShaderLump(frag_lump).GetChars() << "\n";

View file

@ -10,6 +10,8 @@
#include <list>
#include <map>
#include "hwrenderer/postprocessing/hw_useruniforms.h"
class ShaderIncludeResult;
class VulkanRenderDevice;
class VulkanDevice;
@ -122,6 +124,8 @@ class VkShaderProgram
public:
std::unique_ptr<VulkanShader> vert;
std::unique_ptr<VulkanShader> frag;
UniformStructHolder Uniforms;
};
class VkShaderManager
@ -146,8 +150,8 @@ public:
VulkanShader* GetLightTilesShader() { return LightTiles.get(); }
private:
std::unique_ptr<VulkanShader> LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key);
std::unique_ptr<VulkanShader> LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *light_lump_shared, const char *lightmodel_lump, const char *defines, const VkShaderKey& key);
std::unique_ptr<VulkanShader> LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms);
std::unique_ptr<VulkanShader> LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *light_lump_shared, const char *lightmodel_lump, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms);
ShaderIncludeResult OnInclude(FString headerName, FString includerName, size_t depth, bool system);

View file

@ -330,7 +330,7 @@ void VkRenderState::ApplyRenderPass(int dt)
if (changingPipeline)
{
mCommandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey));
mCommandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey, mUniforms));
mPipelineKey = pipelineKey;
}
}
@ -444,7 +444,12 @@ void VkRenderState::ApplyPushConstants()
mPushConstants.uBoneIndexBase = mBoneIndexBase;
mPushConstants.uFogballIndex = mFogballIndex >= 0 ? (mFogballIndex % MAX_FOGBALL_DATA) : -1;
mCommandBuffer->pushConstants(fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants);
mCommandBuffer->pushConstants(fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh, mUniforms.sz), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants);
if(mUniforms.sz > 0)
{
mCommandBuffer->pushConstants(fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh, mUniforms.sz), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, (uint32_t)sizeof(PushConstants), (uint32_t)mUniforms.sz, mUniforms.addr);
}
}
void VkRenderState::ApplyMatrices()
@ -510,7 +515,7 @@ void VkRenderState::ApplyBufferSets()
if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || surfaceUniformsOffset != mLastSurfaceUniformsOffset || lightsOffset != mLastLightsOffset || fogballsOffset != mLastFogballsOffset)
{
auto descriptors = fb->GetDescriptorSetManager();
VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh);
VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh, mUniforms.sz);
uint32_t offsets[5] = { mViewpointOffset, matrixOffset, surfaceUniformsOffset, lightsOffset, fogballsOffset };
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedSet());
@ -1092,14 +1097,14 @@ void VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPip
pushConstants.uBoneIndexBase = -1;
pushConstants.uFogballIndex = -1;
VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(pipelineKey.ShaderKey.UseLevelMesh);
VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(pipelineKey.ShaderKey.UseLevelMesh, mUniforms.sz);
uint32_t viewpointOffset = mViewpointOffset;
uint32_t matrixOffset = mRSBuffers->MatrixBuffer->Offset();
uint32_t fogballsOffset = 0;
uint32_t offsets[] = { viewpointOffset, matrixOffset, fogballsOffset };
auto descriptors = fb->GetDescriptorSetManager();
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey));
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey, mUniforms));
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedSet());
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetLevelMeshSet(), 3, offsets);
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet());

View file

@ -101,6 +101,7 @@ protected:
bool mDepthClamp = true;
VulkanCommandBuffer *mCommandBuffer = nullptr;
VkPipelineKey mPipelineKey = {};
UniformStructHolder mUniforms;
VkRenderPassSetup* mPassSetup = nullptr;
int mClearTargets = 0;
bool mNeedApply = true;

View file

@ -114,8 +114,7 @@ struct UserShaderDesc
bool disablealphatest = false;
uint8_t shaderFlags = 0;
TMap<FString, UserUniformValue> Uniforms;
UserUniforms UniformData;
UserUniforms Uniforms;
};
extern TArray<UserShaderDesc> usershaders;

View file

@ -63,31 +63,34 @@ GlobalShaderDesc globalshaders[NUM_BUILTIN_SHADERS];
struct ExtraUniformCVARData
{
FString Shader;
bool isPP;
int ShaderIndex;
FString Uniform;
void * data = nullptr;
ExtraUniformCVARData* Next = nullptr;
void (*OldCallback)(FBaseCVar &);
};
void pp_uniform_get_data(ExtraUniformCVARData* data)
void uniform_get_data(ExtraUniformCVARData* data)
{
if (!(data->data))
{
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
if(data->isPP)
{
PostProcessShader& shader = PostProcessShaders[i];
if (strcmp(shader.Name.GetChars(), data->Shader.GetChars()) == 0)
{
data->data = shader.Uniforms.GetField(data->Uniform).Value;
}
PostProcessShader& shader = PostProcessShaders[data->ShaderIndex];
data->data = shader.Uniforms.GetField(data->Uniform).Value;
}
else
{
UserShaderDesc& shader = usershaders[data->ShaderIndex];
data->data = shader.Uniforms.GetField(data->Uniform).Value;
}
}
}
static void do_pp_uniform_set1i(int value, ExtraUniformCVARData* data)
static void do_uniform_set1i(int value, ExtraUniformCVARData* data)
{
pp_uniform_get_data(data);
uniform_get_data(data);
int * i1 = (int *)data->data;
if (i1)
@ -96,12 +99,12 @@ static void do_pp_uniform_set1i(int value, ExtraUniformCVARData* data)
}
if (data->Next)
do_pp_uniform_set1i(value, data->Next);
do_uniform_set1i(value, data->Next);
}
static void do_pp_uniform_set1f(float value, ExtraUniformCVARData* data)
static void do_uniform_set1f(float value, ExtraUniformCVARData* data)
{
pp_uniform_get_data(data);
uniform_get_data(data);
float * f1 = (float *)data->data;
if (f1)
@ -110,12 +113,12 @@ static void do_pp_uniform_set1f(float value, ExtraUniformCVARData* data)
}
if (data->Next)
do_pp_uniform_set1f(value, data->Next);
do_uniform_set1f(value, data->Next);
}
static void do_pp_uniform_set2f(float x, float y, ExtraUniformCVARData* data)
static void do_uniform_set2f(float x, float y, ExtraUniformCVARData* data)
{
pp_uniform_get_data(data);
uniform_get_data(data);
float * f2 = (float *)data->data;
if (f2)
@ -125,12 +128,12 @@ static void do_pp_uniform_set2f(float x, float y, ExtraUniformCVARData* data)
}
if (data->Next)
do_pp_uniform_set2f(x, y, data->Next);
do_uniform_set2f(x, y, data->Next);
}
static void do_pp_uniform_set3f(float x, float y, float z, ExtraUniformCVARData* data)
static void do_uniform_set3f(float x, float y, float z, ExtraUniformCVARData* data)
{
pp_uniform_get_data(data);
uniform_get_data(data);
float * f3 = (float *)data->data;
if (f3)
@ -141,12 +144,12 @@ static void do_pp_uniform_set3f(float x, float y, float z, ExtraUniformCVARData*
}
if (data->Next)
do_pp_uniform_set3f(x, y, z, data->Next);
do_uniform_set3f(x, y, z, data->Next);
}
static void do_pp_uniform_set4f(float x, float y, float z, float w, ExtraUniformCVARData* data)
static void do_uniform_set4f(float x, float y, float z, float w, ExtraUniformCVARData* data)
{
pp_uniform_get_data(data);
uniform_get_data(data);
float * f4 = (float *)data->data;
if (f4)
@ -158,28 +161,28 @@ static void do_pp_uniform_set4f(float x, float y, float z, float w, ExtraUniform
}
if (data->Next)
do_pp_uniform_set4f(x, y, z, w, data->Next);
do_uniform_set4f(x, y, z, w, data->Next);
}
template<typename T>
void pp_uniform_callback1i(T &self)
void uniform_callback1i(T &self)
{
auto data = (ExtraUniformCVARData*)self.GetExtraDataPointer2();
if(data->OldCallback) data->OldCallback(self);
do_pp_uniform_set1i(*self, data);
do_uniform_set1i(*self, data);
}
template<typename T>
void pp_uniform_callback1f(T &self)
void uniform_callback1f(T &self)
{
auto data = (ExtraUniformCVARData*)self.GetExtraDataPointer2();
if(data->OldCallback) data->OldCallback(self);
do_pp_uniform_set1f(*self, data);
do_uniform_set1f(*self, data);
}
void pp_uniform_callback_color3f(FColorCVar &self)
void uniform_callback_color3f(FColorCVar &self)
{
auto data = (ExtraUniformCVARData*)self.GetExtraDataPointer2();
if(data->OldCallback) data->OldCallback(self);
@ -187,10 +190,10 @@ void pp_uniform_callback_color3f(FColorCVar &self)
PalEntry col;
col.d = *self;
do_pp_uniform_set3f(col.r / 255.0, col.g / 255.0, col.b / 255.0, data);
do_uniform_set3f(col.r / 255.0, col.g / 255.0, col.b / 255.0, data);
}
void pp_uniform_callback_color4f(FColorCVar &self)
void uniform_callback_color4f(FColorCVar &self)
{
auto data = (ExtraUniformCVARData*)self.GetExtraDataPointer2();
if(data->OldCallback) data->OldCallback(self);
@ -198,7 +201,7 @@ void pp_uniform_callback_color4f(FColorCVar &self)
PalEntry col;
col.d = *self;
do_pp_uniform_set4f(col.r / 255.0, col.g / 255.0, col.b / 255.0, col.a / 255.0, data);
do_uniform_set4f(col.r / 255.0, col.g / 255.0, col.b / 255.0, col.a / 255.0, data);
}
//-----------------------------------------------------------------------------
@ -1403,6 +1406,9 @@ class GLDefsParser
bool iwad = false;
bool no_mipmap = false;
bool hasUniforms = false;
TMap<FString, UserUniformValue> Uniforms;
bool is_globalshader = false;
TArray<int> globaltargets;
FString str_globaltargets;
@ -1612,6 +1618,12 @@ class GLDefsParser
sc.MustGetString();
usershader.vertshader = sc.String;
}
else if (sc.Compare("uniform"))
{
isProperty = true;
hasUniforms = true;
ParseShaderUniform(Uniforms, usershaders.Size(), false);
}
else if (sc.Compare("texture"))
{
isProperty = true;
@ -1822,6 +1834,11 @@ class GLDefsParser
globalshaders[target].shaderindex = usershaders.Push(usershader) + FIRST_USER_SHADER;
if(hasUniforms)
{
usershaders.Last().Uniforms.LoadUniforms(Uniforms);
}
for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++)
{
if (mlay.CustomShaderTextures[i])
@ -1927,20 +1944,29 @@ class GLDefsParser
}
tex->SetShaderSpeed(speed);
for (unsigned i = 0; i < usershaders.Size(); i++)
{
if (!usershaders[i].shader.CompareNoCase(usershader.shader) &&
usershaders[i].shaderType == usershader.shaderType &&
usershaders[i].shaderFlags == usershader.shaderFlags &&
!usershaders[i].defines.Compare(usershader.defines))
if(!hasUniforms)
{ // shaders with uniforms are never reused
for (unsigned i = 0; i < usershaders.Size(); i++)
{
SetShaderIndex(tex, i + FIRST_USER_SHADER);
tex->SetShaderLayers(mlay);
return;
if (!usershaders[i].shader.CompareNoCase(usershader.shader) &&
usershaders[i].shaderType == usershader.shaderType &&
usershaders[i].shaderFlags == usershader.shaderFlags &&
!usershaders[i].defines.Compare(usershader.defines) &&
usershaders[i].Uniforms.UniformStructSize == 0)
{
SetShaderIndex(tex, i + FIRST_USER_SHADER);
tex->SetShaderLayers(mlay);
return;
}
}
}
SetShaderIndex(tex, usershaders.Push(usershader) + FIRST_USER_SHADER);
if(hasUniforms)
{
usershaders.Last().Uniforms.LoadUniforms(Uniforms);
}
}
tex->SetShaderLayers(mlay);
}
@ -1953,18 +1979,247 @@ class GLDefsParser
//
//==========================================================================
void ParseShaderUniform(TMap<FString, UserUniformValue> &Uniforms, int ShaderIndex, bool isPP)
{
bool is_cvar = false;
bool ok = true;
sc.MustGetString();
FString uniformType = sc.String;
uniformType.ToLower();
sc.MustGetString();
FString uniformName = sc.String;
UniformType parsedType = UniformType::Undefined;
if (uniformType.Compare("int") == 0)
{
parsedType = UniformType::Int;
}
else if (uniformType.Compare("float") == 0)
{
parsedType = UniformType::Float;
}
else if (uniformType.Compare("vec2") == 0)
{
parsedType = UniformType::Vec2;
}
else if (uniformType.Compare("vec3") == 0)
{
parsedType = UniformType::Vec3;
}
else if (uniformType.Compare("vec4") == 0)
{
parsedType = UniformType::Vec4;
}
else
{
sc.ScriptError("Unrecognized uniform type '%s'", sc.String);
ok = false;
}
double Values[4] = {0.0, 0.0, 0.0, 1.0};
if(ok && sc.CheckToken('='))
{
if(sc.CheckString("cvar"))
{
is_cvar = true;
}
else switch(parsedType)
{
case UniformType::Int:
sc.MustGetNumber();
Values[0] = sc.BigNumber;
break;
case UniformType::Float:
sc.MustGetFloat();
Values[0] = sc.Float;
break;
case UniformType::Vec2:
sc.MustGetFloat();
Values[0] = sc.Float;
sc.MustGetFloat();
Values[1] = sc.Float;
break;
case UniformType::Vec3:
sc.MustGetFloat();
Values[0] = sc.Float;
sc.MustGetFloat();
Values[1] = sc.Float;
sc.MustGetFloat();
Values[2] = sc.Float;
break;
case UniformType::Vec4:
sc.MustGetFloat();
Values[0] = sc.Float;
sc.MustGetFloat();
Values[1] = sc.Float;
sc.MustGetFloat();
Values[2] = sc.Float;
sc.MustGetFloat();
Values[3] = sc.Float;
break;
}
}
if (ok && !is_cvar)
{
Uniforms[uniformName].Type = parsedType;
Uniforms[uniformName].Values[0] = Values[0];
Uniforms[uniformName].Values[1] = Values[1];
Uniforms[uniformName].Values[2] = Values[2];
Uniforms[uniformName].Values[3] = Values[3];
}
if (ok && is_cvar)
{
FBaseCVar *cvar;
FString cvarname;
void (*callback)(FBaseCVar&) = nullptr;
if(ok)
{
sc.MustGetString();
cvarname = sc.String;
cvar = FindCVar(cvarname.GetChars(), NULL);
if (!cvar)
{
sc.ScriptMessage("Unknown cvar passed to cvar_uniform");
ok = false;
}
}
if(ok)
{
switch (cvar->GetRealType())
{
case CVAR_Bool:
if(parsedType == UniformType::Int)
{
callback = (void (*)(FBaseCVar&))(&uniform_callback1i<FBoolCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Int).Int;
}
else if(parsedType == UniformType::Float)
{
callback = (void (*)(FBaseCVar&))(&uniform_callback1f<FBoolCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Int).Int;
}
else
{
sc.ScriptError("CVar '%s' type (bool) is not convertible to uniform type (%s), must be int or float", cvarname.GetChars(), uniformType.GetChars());
ok = false;
}
break;
case CVAR_Int:
if(parsedType == UniformType::Int)
{
callback = (void (*)(FBaseCVar&))(&uniform_callback1i<FIntCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Int).Int;
}
else if(parsedType == UniformType::Float)
{
callback = (void (*)(FBaseCVar&))(&uniform_callback1f<FIntCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Int).Int;
}
else
{
sc.ScriptError("CVar '%s' type (int) is not convertible to uniform type (%s), must be int or float", cvarname.GetChars(), uniformType.GetChars());
ok = false;
}
break;
case CVAR_Float:
if(parsedType == UniformType::Int)
{
callback = (void (*)(FBaseCVar&))(&uniform_callback1i<FFloatCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Float).Float;
}
else if(parsedType == UniformType::Float)
{
callback = (void (*)(FBaseCVar&))(&uniform_callback1f<FFloatCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Float).Float;
}
else
{
sc.ScriptError("CVar '%s' type (float) is not convertible to uniform type (%s), must be int or float", cvarname.GetChars(), uniformType.GetChars());
ok = false;
}
break;
case CVAR_Color:
if(parsedType == UniformType::Vec3)
{
callback = (void (*)(FBaseCVar&))(&uniform_callback_color3f);
PalEntry col;
col.d = cvar->GetGenericRep(CVAR_Int).Int;
Values[0] = col.r / 255.0;
Values[1] = col.g / 255.0;
Values[2] = col.b / 255.0;
}
else if(parsedType == UniformType::Vec4)
{
callback = (void (*)(FBaseCVar&))(&uniform_callback_color4f);
PalEntry col;
col.d = cvar->GetGenericRep(CVAR_Int).Int;
Values[0] = col.r / 255.0;
Values[1] = col.g / 255.0;
Values[2] = col.b / 255.0;
Values[3] = col.a / 255.0;
}
else
{
sc.ScriptError("CVar '%s' type (color) is not convertible to uniform type (%s), must be vec3 or vec4", cvarname.GetChars(), uniformType.GetChars());
ok = false;
}
break;
default:
sc.ScriptError("CVar '%s' type not supported for uniforms!", cvarname.GetChars());
ok = false;
break;
}
}
if(ok)
{
ExtraUniformCVARData* oldextra = (ExtraUniformCVARData*) cvar->GetExtraDataPointer2();
ExtraUniformCVARData* extra = new ExtraUniformCVARData;
extra->isPP = isPP;
extra->ShaderIndex = ShaderIndex;
extra->Uniform = uniformName.GetChars();
extra->OldCallback = oldextra ? oldextra->OldCallback : cvar->m_Callback;
extra->Next = oldextra;
cvar->SetCallback(callback);
cvar->SetExtraDataPointer2(extra);
Uniforms[uniformName].Type = parsedType;
Uniforms[uniformName].Values[0] = Values[0];
Uniforms[uniformName].Values[1] = Values[1];
Uniforms[uniformName].Values[2] = Values[2];
Uniforms[uniformName].Values[3] = Values[3];
}
}
}
void ParseHardwareShader()
{
sc.MustGetString();
if (sc.Compare("postprocess"))
{
sc.MustGetString();
PostProcessShader shaderdesc;
TMap<FString, UserUniformValue> Uniforms;
shaderdesc.Target = sc.String;
shaderdesc.Target.ToLower();
bool hasUniforms = false;
bool validTarget = false;
if (sc.Compare("beforebloom")) validTarget = true;
if (sc.Compare("scene")) validTarget = true;
@ -1993,215 +2248,8 @@ class GLDefsParser
}
else if (sc.Compare("uniform"))
{
bool is_cvar = false;
bool ok = true;
sc.MustGetString();
FString uniformType = sc.String;
uniformType.ToLower();
sc.MustGetString();
FString uniformName = sc.String;
UniformType parsedType = UniformType::Undefined;
if (uniformType.Compare("int") == 0)
{
parsedType = UniformType::Int;
}
else if (uniformType.Compare("float") == 0)
{
parsedType = UniformType::Float;
}
else if (uniformType.Compare("vec2") == 0)
{
parsedType = UniformType::Vec2;
}
else if (uniformType.Compare("vec3") == 0)
{
parsedType = UniformType::Vec3;
}
else if (uniformType.Compare("vec4") == 0)
{
parsedType = UniformType::Vec4;
}
else
{
sc.ScriptError("Unrecognized uniform type '%s'", sc.String);
ok = false;
}
double Values[4] = {0.0, 0.0, 0.0, 1.0};
if(ok && sc.CheckToken('='))
{
if(sc.CheckString("cvar"))
{
is_cvar = true;
}
else switch(parsedType)
{
case UniformType::Int:
sc.MustGetNumber();
Values[0] = sc.BigNumber;
break;
case UniformType::Float:
sc.MustGetFloat();
Values[0] = sc.Float;
break;
case UniformType::Vec2:
sc.MustGetFloat();
Values[0] = sc.Float;
sc.MustGetFloat();
Values[1] = sc.Float;
break;
case UniformType::Vec3:
sc.MustGetFloat();
Values[0] = sc.Float;
sc.MustGetFloat();
Values[1] = sc.Float;
sc.MustGetFloat();
Values[2] = sc.Float;
break;
case UniformType::Vec4:
sc.MustGetFloat();
Values[0] = sc.Float;
sc.MustGetFloat();
Values[1] = sc.Float;
sc.MustGetFloat();
Values[2] = sc.Float;
sc.MustGetFloat();
Values[3] = sc.Float;
break;
}
}
if (ok && !is_cvar)
{
Uniforms[uniformName].Type = parsedType;
Uniforms[uniformName].Values[0] = Values[0];
Uniforms[uniformName].Values[1] = Values[1];
Uniforms[uniformName].Values[2] = Values[2];
Uniforms[uniformName].Values[3] = Values[3];
}
if (ok && is_cvar)
{
if (shaderdesc.Name.IsEmpty())
sc.ScriptError("Shader must have a name to use cvar uniforms");
int cvarflags = CVAR_MOD|CVAR_ARCHIVE|CVAR_VIRTUAL;
FBaseCVar *cvar;
FString cvarname;
void (*callback)(FBaseCVar&) = nullptr;
if(ok)
{
sc.MustGetString();
cvarname = sc.String;
cvar = FindCVar(cvarname.GetChars(), NULL);
if (!cvar)
{
sc.ScriptMessage("Unknown cvar passed to cvar_uniform");
ok = false;
}
}
if(ok)
{
switch (cvar->GetRealType())
{
case CVAR_Int:
if(parsedType == UniformType::Int)
{
callback = (void (*)(FBaseCVar&))(&pp_uniform_callback1i<FIntCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Int).Int;
}
else if(parsedType == UniformType::Float)
{
callback = (void (*)(FBaseCVar&))(&pp_uniform_callback1f<FIntCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Int).Int;
}
else
{
sc.ScriptError("CVar '%s' type (int) is not convertible to uniform type (%s), must be int or float", cvarname.GetChars(), uniformType.GetChars());
ok = false;
}
break;
case CVAR_Float:
if(parsedType == UniformType::Int)
{
callback = (void (*)(FBaseCVar&))(&pp_uniform_callback1i<FFloatCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Float).Float;
}
else if(parsedType == UniformType::Float)
{
callback = (void (*)(FBaseCVar&))(&pp_uniform_callback1f<FFloatCVar>);
Values[0] = cvar->GetGenericRep(CVAR_Float).Float;
}
else
{
sc.ScriptError("CVar '%s' type (float) is not convertible to uniform type (%s), must be int or float", cvarname.GetChars(), uniformType.GetChars());
ok = false;
}
break;
case CVAR_Color:
if(parsedType == UniformType::Vec3)
{
callback = (void (*)(FBaseCVar&))(&pp_uniform_callback_color3f);
PalEntry col;
col.d = cvar->GetGenericRep(CVAR_Int).Int;
Values[0] = col.r / 255.0;
Values[1] = col.g / 255.0;
Values[2] = col.b / 255.0;
}
else if(parsedType == UniformType::Vec4)
{
callback = (void (*)(FBaseCVar&))(&pp_uniform_callback_color4f);
PalEntry col;
col.d = cvar->GetGenericRep(CVAR_Int).Int;
Values[0] = col.r / 255.0;
Values[1] = col.g / 255.0;
Values[2] = col.b / 255.0;
Values[3] = col.a / 255.0;
}
else
{
sc.ScriptError("CVar '%s' type (color) is not convertible to uniform type (%s), must be vec3 or vec4", cvarname.GetChars(), uniformType.GetChars());
ok = false;
}
break;
default:
sc.ScriptError("CVar '%s' type not supported for uniforms!", cvarname.GetChars());
ok = false;
break;
}
}
if(ok)
{
ExtraUniformCVARData* oldextra = (ExtraUniformCVARData*)cvar->GetExtraDataPointer2();
ExtraUniformCVARData* extra = new ExtraUniformCVARData;
extra->Shader = shaderdesc.Name.GetChars();
extra->Uniform = uniformName.GetChars();
extra->OldCallback = oldextra ? oldextra->OldCallback : cvar->m_Callback;
extra->Next = oldextra;
cvar->SetCallback(callback);
cvar->SetExtraDataPointer2(extra);
Uniforms[uniformName].Type = parsedType;
Uniforms[uniformName].Values[0] = Values[0];
Uniforms[uniformName].Values[1] = Values[1];
Uniforms[uniformName].Values[2] = Values[2];
Uniforms[uniformName].Values[3] = Values[3];
}
}
hasUniforms = true;
ParseShaderUniform(Uniforms, PostProcessShaders.Size(), true);
}
else if (sc.Compare("texture"))
{
@ -2224,7 +2272,11 @@ class GLDefsParser
}
auto index = PostProcessShaders.Push(shaderdesc);
PostProcessShaders[index].Uniforms.LoadUniforms(Uniforms);
if(hasUniforms)
{
PostProcessShaders.Last().Uniforms.LoadUniforms(Uniforms);
}
}
else
{

View file

@ -3,20 +3,6 @@
#include "shaders/scene/binding_rsbuffers.glsl"
#include "shaders/scene/binding_textures.glsl"
// This must match the PushConstants struct
layout(push_constant) uniform PushConstants
{
#if defined(USE_LEVELMESH)
int unused0;
int unused1;
#else
int uDataIndex; // surfaceuniforms index
int uLightIndex; // dynamic lights
#endif
int uBoneIndexBase; // bone animation
int uFogballIndex; // fog balls
};
// material types
#if defined(SPECULAR)
#define normaltexture texture2