From ea09ae14617e6ff8174c4cb49ee9db0f0fbecb91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Wed, 8 Jan 2025 06:07:29 -0300 Subject: [PATCH] implement custom uniforms for material shaders --- .../postprocessing/hw_postprocess.cpp | 2 +- .../postprocessing/hw_useruniforms.h | 5 +- .../vulkan/pipelines/vk_renderpass.cpp | 34 +- .../vulkan/pipelines/vk_renderpass.h | 14 +- .../rendering/vulkan/shaders/vk_ppshader.cpp | 4 +- .../rendering/vulkan/shaders/vk_ppshader.h | 1 - .../rendering/vulkan/shaders/vk_shader.cpp | 50 +- .../rendering/vulkan/shaders/vk_shader.h | 8 +- .../rendering/vulkan/vk_renderstate.cpp | 15 +- src/common/rendering/vulkan/vk_renderstate.h | 1 + src/common/textures/textures.h | 3 +- src/r_data/gldefs.cpp | 554 ++++++++++-------- .../static/shaders/scene/layout_shared.glsl | 14 - 13 files changed, 406 insertions(+), 299 deletions(-) diff --git a/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp index 892d308f7..a58a97c66 100644 --- a/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp @@ -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; diff --git a/src/common/rendering/hwrenderer/postprocessing/hw_useruniforms.h b/src/common/rendering/hwrenderer/postprocessing/hw_useruniforms.h index 66a55a8b4..968383de2 100644 --- a/src/common/rendering/hwrenderer/postprocessing/hw_useruniforms.h +++ b/src/common/rendering/hwrenderer/postprocessing/hw_useruniforms.h @@ -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 &Uniforms); - void WriteUniforms(UniformStructHolder &Data); + void WriteUniforms(UniformStructHolder &Data) const; int UniformStructSize = 0; diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp index 8c63b586d..0fa751f00 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp @@ -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{key, PipelineData{std::move(pipeline), Uniforms}}); + return ptr; + } + else + { + Uniforms = item->second.Uniforms; + return item->second.pipeline.get(); + } } -std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key) +std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms) { GraphicsPipelineBuilder builder; builder.Cache(fb->GetRenderPassManager()->GetCache()); @@ -365,10 +381,12 @@ std::unique_ptr 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()); } diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.h b/src/common/rendering/vulkan/pipelines/vk_renderpass.h index 9f9854ae5..2b1fe62dd 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.h +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.h @@ -69,21 +69,27 @@ public: bool operator!=(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) != 0; } }; +struct PipelineData +{ + std::unique_ptr 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 RenderPasses[8]; - std::map> Pipelines; + std::map Pipelines; private: std::unique_ptr CreateRenderPass(int clearTargets); - std::unique_ptr CreatePipeline(const VkPipelineKey &key); + std::unique_ptr CreatePipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms); VulkanRenderDevice* fb = nullptr; }; @@ -109,7 +115,7 @@ public: VkRenderPassSetup *GetRenderPass(const VkRenderPassKey &key); int GetVertexFormat(const std::vector& bufferStrides, const std::vector& attrs); VkVertexFormat *GetVertexFormat(int index); - VulkanPipelineLayout* GetPipelineLayout(bool levelmesh); + VulkanPipelineLayout* GetPipelineLayout(bool levelmesh, int UserUniformSize); VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key); diff --git a/src/common/rendering/vulkan/shaders/vk_ppshader.cpp b/src/common/rendering/vulkan/shaders/vk_ppshader.cpp index 25a903091..3fa7cbd90 100644 --- a/src/common/rendering/vulkan/shaders/vk_ppshader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_ppshader.cpp @@ -138,14 +138,14 @@ FString VkPPShader::CreateUniformBlockDecl(const char* name, const std::vector& 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); diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 3f380d544..9e8b2621f 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -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 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 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 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 VkShaderManager::LoadVertShader(FString shadername .Create(shadername.GetChars(), fb->GetDevice()); } -std::unique_ptr 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 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 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"; diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index b3938fdd8..4c83f53a6 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -10,6 +10,8 @@ #include #include +#include "hwrenderer/postprocessing/hw_useruniforms.h" + class ShaderIncludeResult; class VulkanRenderDevice; class VulkanDevice; @@ -122,6 +124,8 @@ class VkShaderProgram public: std::unique_ptr vert; std::unique_ptr frag; + + UniformStructHolder Uniforms; }; class VkShaderManager @@ -146,8 +150,8 @@ public: VulkanShader* GetLightTilesShader() { return LightTiles.get(); } private: - std::unique_ptr LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key); - std::unique_ptr 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 LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms); + std::unique_ptr 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); diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index fca1758aa..7c76b98ec 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -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()); diff --git a/src/common/rendering/vulkan/vk_renderstate.h b/src/common/rendering/vulkan/vk_renderstate.h index 163ce72bf..ca5fc87f9 100644 --- a/src/common/rendering/vulkan/vk_renderstate.h +++ b/src/common/rendering/vulkan/vk_renderstate.h @@ -101,6 +101,7 @@ protected: bool mDepthClamp = true; VulkanCommandBuffer *mCommandBuffer = nullptr; VkPipelineKey mPipelineKey = {}; + UniformStructHolder mUniforms; VkRenderPassSetup* mPassSetup = nullptr; int mClearTargets = 0; bool mNeedApply = true; diff --git a/src/common/textures/textures.h b/src/common/textures/textures.h index d6fdbb726..4f4c13618 100644 --- a/src/common/textures/textures.h +++ b/src/common/textures/textures.h @@ -114,8 +114,7 @@ struct UserShaderDesc bool disablealphatest = false; uint8_t shaderFlags = 0; - TMap Uniforms; - UserUniforms UniformData; + UserUniforms Uniforms; }; extern TArray usershaders; diff --git a/src/r_data/gldefs.cpp b/src/r_data/gldefs.cpp index cd6a7d3a5..d28179dd4 100644 --- a/src/r_data/gldefs.cpp +++ b/src/r_data/gldefs.cpp @@ -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 -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 -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 Uniforms; + bool is_globalshader = false; TArray 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 &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); + Values[0] = cvar->GetGenericRep(CVAR_Int).Int; + } + else if(parsedType == UniformType::Float) + { + callback = (void (*)(FBaseCVar&))(&uniform_callback1f); + 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); + Values[0] = cvar->GetGenericRep(CVAR_Int).Int; + } + else if(parsedType == UniformType::Float) + { + callback = (void (*)(FBaseCVar&))(&uniform_callback1f); + 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); + Values[0] = cvar->GetGenericRep(CVAR_Float).Float; + } + else if(parsedType == UniformType::Float) + { + callback = (void (*)(FBaseCVar&))(&uniform_callback1f); + 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 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); - Values[0] = cvar->GetGenericRep(CVAR_Int).Int; - } - else if(parsedType == UniformType::Float) - { - callback = (void (*)(FBaseCVar&))(&pp_uniform_callback1f); - 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); - Values[0] = cvar->GetGenericRep(CVAR_Float).Float; - } - else if(parsedType == UniformType::Float) - { - callback = (void (*)(FBaseCVar&))(&pp_uniform_callback1f); - 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 { diff --git a/wadsrc/static/shaders/scene/layout_shared.glsl b/wadsrc/static/shaders/scene/layout_shared.glsl index f1fef42cc..6760f1b5e 100644 --- a/wadsrc/static/shaders/scene/layout_shared.glsl +++ b/wadsrc/static/shaders/scene/layout_shared.glsl @@ -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