From 202d99bf9ea82a44cd95513b0be0ef260e77bdfd Mon Sep 17 00:00:00 2001 From: dpjudas Date: Thu, 10 Apr 2025 08:17:45 +0200 Subject: [PATCH] Add worker thread for creating pipelines --- .../vulkan/pipelines/vk_renderpass.cpp | 387 ++++++++++++++---- .../vulkan/pipelines/vk_renderpass.h | 30 +- .../rendering/vulkan/shaders/vk_shader.cpp | 10 +- .../rendering/vulkan/shaders/vk_shader.h | 2 +- .../rendering/vulkan/vk_renderdevice.cpp | 2 + .../shaders/scene/lightmodel_normal.glsl | 6 + .../static/shaders/scene/lightmodel_pbr.glsl | 2 + .../shaders/scene/lightmodel_specular.glsl | 4 + 8 files changed, 343 insertions(+), 100 deletions(-) diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp index 0bda8182d..b140692aa 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp @@ -37,6 +37,24 @@ #include "i_specialpaths.h" #include "cmdlib.h" +CVAR(Bool, gl_ubershaders, true, 0); +CVAR(Bool, vk_debug_pipeline_creation, true, 0); + +// Pipeline creation tracking and printing +int Printf(const char* fmt, ...); +static double pipeline_time; +static int pipeline_count; +ADD_STAT(pipelines) +{ + FString out; + out.Format( + "Pipelines created: %d\n" + "Pipeline time: %.3f\n" + "Pipeline average: %.3f", + pipeline_count, pipeline_time, pipeline_time / pipeline_count); + return out; +} + VkRenderPassManager::VkRenderPassManager(VulkanRenderDevice* fb) : fb(fb) { FString path = M_GetCachePath(true); @@ -65,12 +83,16 @@ VkRenderPassManager::VkRenderPassManager(VulkanRenderDevice* fb) : fb(fb) PipelineCache = builder.Create(fb->GetDevice()); + Worker.Thread = std::thread([this]() { WorkerThreadMain(); }); + CreateLightTilesPipeline(); CreateZMinMaxPipeline(); } VkRenderPassManager::~VkRenderPassManager() { + StopWorkerThread(); + try { auto data = PipelineCache->GetCacheData(); @@ -83,6 +105,80 @@ VkRenderPassManager::~VkRenderPassManager() } } +void VkRenderPassManager::ProcessMainThreadTasks() +{ + std::unique_lock lock(Worker.Mutex); + std::vector> tasks; + tasks.swap(Worker.MainTasks); + lock.unlock(); + + for (auto& task : tasks) + { + task(); + } +} + +void VkRenderPassManager::RunOnWorkerThread(std::function task) +{ + std::unique_lock lock(Worker.Mutex); + Worker.WorkerTasks.push_back(std::move(task)); + lock.unlock(); + Worker.CondVar.notify_one(); +} + +void VkRenderPassManager::RunOnMainThread(std::function task) +{ + std::unique_lock lock(Worker.Mutex); + Worker.MainTasks.push_back(std::move(task)); +} + +void VkRenderPassManager::StopWorkerThread() +{ + std::unique_lock lock(Worker.Mutex); + Worker.StopFlag = true; + lock.unlock(); + Worker.CondVar.notify_all(); + Worker.Thread.join(); + lock.lock(); + Worker.MainTasks.clear(); + Worker.WorkerTasks.clear(); + Worker.StopFlag = false; +} + +void VkRenderPassManager::WorkerThreadMain() +{ + std::unique_lock lock(Worker.Mutex); + while (true) + { + Worker.CondVar.wait(lock, [&] { return Worker.StopFlag || !Worker.WorkerTasks.empty(); }); + if (Worker.StopFlag) + break; + + std::vector> tasks; + tasks.swap(Worker.WorkerTasks); + lock.unlock(); + + try + { + for (auto& task : tasks) + { + lock.lock(); + if (Worker.StopFlag) + return; + lock.unlock(); + task(); + } + } + catch (...) + { + auto exception = std::current_exception(); + RunOnMainThread([=]() { std::rethrow_exception(exception); }); + } + + lock.lock(); + } +} + void VkRenderPassManager::RenderBuffersReset() { RenderPassSetup.clear(); @@ -213,35 +309,44 @@ void VkRenderPassManager::CreateZMinMaxPipeline() VkRenderPassSetup::VkRenderPassSetup(VulkanRenderDevice* fb, const VkRenderPassKey &key) : PassKey(key), fb(fb) { - // To do: don't do it here as that will block the main thread. - // Precompile material fragment shaders: -/* - VkPipelineKey fkey; - fkey.IsGeneralized = true; - fkey.DepthFunc = DF_LEqual; - fkey.StencilTest = true; - fkey.StencilPassOp = SOP_Keep; - fkey.ShaderKey.Layout.Simple = 0; - fkey.ShaderKey.Layout.Simple3D = 0; - fkey.ShaderKey.Layout.GBufferPass = gl_ssao != 0; - fkey.ShaderKey.Layout.UseLevelMesh = 0; - - int count = NUM_BUILTIN_SHADERS + usershaders.Size(); - for (int i = 0; i < count; i++) + if (gl_ubershaders) { - fkey.ShaderKey.SpecialEffect = EFF_NONE; - fkey.ShaderKey.EffectState = i; - for (int j = 0; j < 16; j++) + VkPipelineKey fkey; + fkey.IsGeneralized = true; + fkey.DepthFunc = DF_LEqual; + fkey.StencilTest = true; + fkey.StencilPassOp = SOP_Keep; + fkey.ShaderKey.Layout.Simple = 0; + fkey.ShaderKey.Layout.Simple3D = 0; + fkey.ShaderKey.Layout.GBufferPass = gl_ssao != 0; + fkey.ShaderKey.Layout.UseLevelMesh = 0; + + // Ignore these. They all look horrible. We should delete them. + bool skip[NUM_BUILTIN_SHADERS] = {}; + skip[SHADER_BasicFuzz] = true; + skip[SHADER_SmoothFuzz] = true; + skip[SHADER_SwirlyFuzz] = true; + skip[SHADER_TranslucentFuzz] = true; + skip[SHADER_JaggedFuzz] = true; + skip[SHADER_NoiseFuzz] = true; + skip[SHADER_SmoothNoiseFuzz] = true; + + int count = NUM_BUILTIN_SHADERS + usershaders.Size(); + for (int i = 0; i < count; i++) { - fkey.DepthWrite = (j & 1) != 0; - fkey.DepthTest = (j & 2) != 0; - fkey.ShaderKey.Layout.AlphaTest = (j & 4) != 0; - fkey.ShaderKey.Layout.ShadeVertex = (j & 8) != 0; - GetFragmentShaderLibrary(fkey, true); + fkey.ShaderKey.SpecialEffect = EFF_NONE; + fkey.ShaderKey.EffectState = i; + for (int j = 0; j < 16; j++) + { + fkey.DepthWrite = (j & 1) != 0; + fkey.DepthTest = (j & 2) != 0; + fkey.ShaderKey.Layout.AlphaTest = (j & 4) != 0; + fkey.ShaderKey.Layout.ShadeVertex = (j & 8) != 0; + PrecompileFragmentShaderLibrary(fkey, true); + } } } -*/ } std::unique_ptr VkRenderPassSetup::CreateRenderPass(int clearTargets) @@ -303,39 +408,22 @@ VulkanRenderPass *VkRenderPassSetup::GetRenderPass(int clearTargets) return RenderPasses[clearTargets].get(); } -CVAR(Bool, gl_ubershaders, false, 0); // development variable - VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms) { - // To do: - // Build the generalized pipelines in the VkRenderPassSetup constructor - // Then build the specialized ones on a worker thread - if (gl_ubershaders) { - VkPipelineKey gkey = key; - gkey.ShaderKey.AsQWORD = 0; - - auto item = GeneralizedPipelines.find(gkey); - if (item == GeneralizedPipelines.end()) - { - auto pipeline = LinkPipeline(gkey, true, Uniforms); - auto ptr = pipeline.get(); - GeneralizedPipelines.insert(std::pair{gkey, PipelineData{ std::move(pipeline), Uniforms }}); - return ptr; - } - else - { - Uniforms = item->second.Uniforms; - return item->second.pipeline.get(); - } + auto data = GetSpecializedPipeline(key); + if (!data) + data = GetGeneralizedPipeline(key); + Uniforms = data->Uniforms; + return data->pipeline.get(); } else { auto item = SpecializedPipelines.find(key); if (item == SpecializedPipelines.end()) { - auto pipeline = CreatePipeline(key, false, Uniforms); + auto pipeline = CreateWithStats(*CreatePipeline(key, false, Uniforms), "Specialized"); auto ptr = pipeline.get(); SpecializedPipelines.insert(std::pair{key, PipelineData{std::move(pipeline), Uniforms}}); return ptr; @@ -348,23 +436,91 @@ VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key, Uniform } } -// Pipeline creation tracking and printing -int Printf(const char* fmt, ...); -CVAR(Bool, vk_debug_pipeline_creation, false, 0); -static double pipeline_time; -static int pipeline_count; -ADD_STAT(pipelines) +PipelineData* VkRenderPassSetup::GetSpecializedPipeline(const VkPipelineKey& key) { - FString out; - out.Format( - "Pipelines created: %d\n" - "Pipeline time: %.3f\n" - "Pipeline average: %.3f", - pipeline_count, pipeline_time, pipeline_time / pipeline_count); - return out; + // Have we seen this before? + auto it = SpecializedPipelines.find(key); + if (it != SpecializedPipelines.end()) + { + // Yes. Do we have the pipeline yet? + if (it->second.pipeline) + { + // Yes. + return &it->second; + } + // No, it is still building. + return nullptr; + } + else + { + // We haven't seen this before. Build it on the worker thread. + + struct TaskData + { + std::unique_ptr builder; + std::unique_ptr pipeline; + }; + + auto data = std::make_shared(); + + // Compile the GLSL on the main thread (mainly due to the resource system) + UniformStructHolder uniforms; + data->builder = CreatePipeline(key, false, uniforms); + SpecializedPipelines[key].Uniforms = uniforms; + + // Schedule the pipeline building on a worker thread + VkPipelineKey k = key; + auto passManager = fb->GetRenderPassManager(); + passManager->RunOnWorkerThread([=]() { + + cycle_t ct; + ct.ResetAndClock(); + data->pipeline = data->builder->Create(fb->GetDevice()); + ct.Unclock(); + const auto duration = ct.TimeMS(); + + passManager->RunOnMainThread([=]() { + auto& slot = SpecializedPipelines[k]; + if (!slot.pipeline) + slot.pipeline = std::move(data->pipeline); + + pipeline_time += duration; + ++pipeline_count; + + if (vk_debug_pipeline_creation) + { + Printf(">>> Pipeline created in %.3fms (Specialized worker)\n", duration); + } + }); + }); + + return nullptr; + } } -std::unique_ptr VkRenderPassSetup::CreateWithStats(GraphicsPipelineBuilder& builder) +PipelineData* VkRenderPassSetup::GetGeneralizedPipeline(const VkPipelineKey& key) +{ + VkPipelineKey gkey = key; + gkey.ShaderKey.AsQWORD = 0; + + auto item = GeneralizedPipelines.find(gkey); + if (item == GeneralizedPipelines.end()) + { + UniformStructHolder uniforms; + auto pipeline = LinkPipeline(gkey, true, uniforms); + auto ptr = pipeline.get(); + auto& value = GeneralizedPipelines[gkey]; + value.pipeline = std::move(pipeline); + value.Uniforms = uniforms; + return &value; + } + else + { + return &item->second; + } +} + +std::unique_ptr VkRenderPassSetup::CreateWithStats(GraphicsPipelineBuilder& builder, const char* type) { cycle_t ct; ct.ResetAndClock(); @@ -378,31 +534,31 @@ std::unique_ptr VkRenderPassSetup::CreateWithStats(GraphicsPipel if (vk_debug_pipeline_creation) { - Printf(">>> Pipeline created in %.3fms\n", duration); + Printf(">>> Pipeline created in %.3fms (%s)\n", duration, type); } return pipeline; } -std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipelineKey& key, bool isUberShader, UniformStructHolder& Uniforms) +std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipelineKey& key, bool isUberShader, UniformStructHolder& Uniforms) { VkShaderProgram* program = fb->GetShaderManager()->Get(key.ShaderKey, isUberShader); Uniforms.Clear(); Uniforms = program->Uniforms; - GraphicsPipelineBuilder builder; - builder.Cache(fb->GetRenderPassManager()->GetCache()); - builder.Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.ShaderKey.Layout.UseLevelMesh, program->Uniforms.sz)); - builder.RenderPass(GetRenderPass(0)); - builder.DebugName("VkRenderPassSetup.Pipeline"); + auto builder = std::make_unique(); + builder->Cache(fb->GetRenderPassManager()->GetCache()); + builder->Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.ShaderKey.Layout.UseLevelMesh, program->Uniforms.sz)); + builder->RenderPass(GetRenderPass(0)); + builder->DebugName("VkRenderPassSetup.Pipeline"); - AddVertexInputInterface(builder, key.ShaderKey.VertexFormat, key.DrawType); - AddPreRasterizationShaders(builder, key, program); - AddFragmentShader(builder, key, program); - AddFragmentOutputInterface(builder, key.RenderStyle, (VkColorComponentFlags)key.ColorMask); - AddDynamicState(builder); + AddVertexInputInterface(*builder, key.ShaderKey.VertexFormat, key.DrawType); + AddPreRasterizationShaders(*builder, key, program); + AddFragmentShader(*builder, key, program); + AddFragmentOutputInterface(*builder, key.RenderStyle, (VkColorComponentFlags)key.ColorMask); + AddDynamicState(*builder); - return CreateWithStats(builder); + return builder; } VulkanPipeline* VkRenderPassSetup::GetVertexInputLibrary(int vertexFormat, int drawType, bool useLevelMesh, int userUniformSize) @@ -471,7 +627,7 @@ VulkanPipeline* VkRenderPassSetup::GetVertexShaderLibrary(const VkPipelineKey& k return pipeline.get(); } -VulkanPipeline* VkRenderPassSetup::GetFragmentShaderLibrary(const VkPipelineKey& key, bool isUberShader) +VkPipelineKey VkRenderPassSetup::GetFragmentShaderKey(const VkPipelineKey& key, bool isUberShader) { VkPipelineKey fkey = key; fkey.IsGeneralized = isUberShader; @@ -485,9 +641,58 @@ VulkanPipeline* VkRenderPassSetup::GetFragmentShaderLibrary(const VkPipelineKey& fkey.ShaderKey.VertexFormat = 0; if (isUberShader) fkey.ShaderKey.AsQWORD = 0; + return fkey; +} + +void VkRenderPassSetup::PrecompileFragmentShaderLibrary(const VkPipelineKey& key, bool isUberShader) +{ + VkPipelineKey fkey = GetFragmentShaderKey(key, isUberShader); + auto it = Libraries.FragmentShader.find(fkey); + if (it == Libraries.FragmentShader.end()) + { + Libraries.FragmentShader[fkey] = nullptr; + + struct TaskData + { + std::unique_ptr builder; + std::unique_ptr pipeline; + }; + + auto data = std::make_shared(); + data->builder = CreateFragmentShaderLibrary(key, isUberShader); + + auto passManager = fb->GetRenderPassManager(); + passManager->RunOnWorkerThread([=]() { + + cycle_t ct; + ct.ResetAndClock(); + data->pipeline = data->builder->Create(fb->GetDevice()); + ct.Unclock(); + const auto duration = ct.TimeMS(); + + passManager->RunOnMainThread([=]() { + auto& slot = Libraries.FragmentShader[fkey]; + if (!slot) + slot = std::move(data->pipeline); + + pipeline_time += duration; + ++pipeline_count; + + if (vk_debug_pipeline_creation) + { + Printf(">>> Pipeline created in %.3fms (FragmentShaderLibrary worker)\n", duration); + } + }); + }); + } +} + +VulkanPipeline* VkRenderPassSetup::GetFragmentShaderLibrary(const VkPipelineKey& key, bool isUberShader) +{ + VkPipelineKey fkey = GetFragmentShaderKey(key, isUberShader); auto& pipeline = Libraries.FragmentShader[fkey]; if (!pipeline) - pipeline = CreateFragmentShaderLibrary(key, isUberShader); + pipeline = CreateWithStats(*CreateFragmentShaderLibrary(key, isUberShader), "FragmentShaderLibrary"); return pipeline.get(); } @@ -504,7 +709,7 @@ std::unique_ptr VkRenderPassSetup::LinkPipeline(const VkPipeline builder.AddLibrary(GetVertexShaderLibrary(key, isUberShader)); builder.AddLibrary(GetFragmentShaderLibrary(key, isUberShader)); builder.AddLibrary(GetFragmentOutputLibrary(key.RenderStyle, (VkColorComponentFlags)key.ColorMask)); - return CreateWithStats(builder); + return CreateWithStats(builder, "Generalized"); } std::unique_ptr VkRenderPassSetup::CreateVertexInputLibrary(int vertexFormat, int drawType, bool useLevelMesh, int userUniformSize) @@ -518,7 +723,7 @@ std::unique_ptr VkRenderPassSetup::CreateVertexInputLibrary(int builder.DebugName("VkRenderPassSetup.VertexInputLibrary"); AddVertexInputInterface(builder, vertexFormat, drawType); AddDynamicState(builder); - return CreateWithStats(builder); + return CreateWithStats(builder, "VertexInputLibrary"); } std::unique_ptr VkRenderPassSetup::CreateVertexShaderLibrary(const VkPipelineKey& key, bool isUberShader) @@ -533,22 +738,22 @@ std::unique_ptr VkRenderPassSetup::CreateVertexShaderLibrary(con builder.DebugName("VkRenderPassSetup.VertexShaderLibrary"); AddPreRasterizationShaders(builder, key, program); AddDynamicState(builder); - return CreateWithStats(builder); + return CreateWithStats(builder, "VertexShaderLibrary"); } -std::unique_ptr VkRenderPassSetup::CreateFragmentShaderLibrary(const VkPipelineKey& key, bool isUberShader) +std::unique_ptr VkRenderPassSetup::CreateFragmentShaderLibrary(const VkPipelineKey& key, bool isUberShader) { VkShaderProgram* program = fb->GetShaderManager()->Get(key.ShaderKey, isUberShader); - GraphicsPipelineBuilder builder; - builder.Cache(fb->GetRenderPassManager()->GetCache()); - builder.Flags(VK_PIPELINE_CREATE_LIBRARY_BIT_KHR); - builder.LibraryFlags(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT); - builder.Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.ShaderKey.Layout.UseLevelMesh, program->Uniforms.sz)); - builder.RenderPass(GetRenderPass(0)); - builder.DebugName("VkRenderPassSetup.FragmentShaderLibrary"); - AddFragmentShader(builder, key, program); - AddDynamicState(builder); - return CreateWithStats(builder); + auto builder = std::make_unique(); + builder->Cache(fb->GetRenderPassManager()->GetCache()); + builder->Flags(VK_PIPELINE_CREATE_LIBRARY_BIT_KHR); + builder->LibraryFlags(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT); + builder->Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.ShaderKey.Layout.UseLevelMesh, program->Uniforms.sz)); + builder->RenderPass(GetRenderPass(0)); + builder->DebugName("VkRenderPassSetup.FragmentShaderLibrary"); + AddFragmentShader(*builder, key, program); + AddDynamicState(*builder); + return builder; } std::unique_ptr VkRenderPassSetup::CreateFragmentOutputLibrary(FRenderStyle renderStyle, VkColorComponentFlags colorMask) @@ -561,7 +766,7 @@ std::unique_ptr VkRenderPassSetup::CreateFragmentOutputLibrary(F builder.DebugName("VkRenderPassSetup.FragmentOutputLibrary"); AddFragmentOutputInterface(builder, renderStyle, colorMask); AddDynamicState(builder); - return CreateWithStats(builder); + return CreateWithStats(builder, "FragmentOutputLibrary"); } void VkRenderPassSetup::AddVertexInputInterface(GraphicsPipelineBuilder& builder, int vertexFormat, int drawType) diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.h b/src/common/rendering/vulkan/pipelines/vk_renderpass.h index c0a50a4d8..801d00857 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.h +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.h @@ -89,9 +89,15 @@ public: private: std::unique_ptr CreateRenderPass(int clearTargets); - std::unique_ptr CreatePipeline(const VkPipelineKey &key, bool isUberShader, UniformStructHolder &Uniforms); + std::unique_ptr CreatePipeline(const VkPipelineKey &key, bool isUberShader, UniformStructHolder &Uniforms); std::unique_ptr LinkPipeline(const VkPipelineKey& key, bool isUberShader, UniformStructHolder& Uniforms); - std::unique_ptr CreateWithStats(GraphicsPipelineBuilder& builder); + std::unique_ptr CreateWithStats(GraphicsPipelineBuilder& builder, const char* type); + + PipelineData* GetSpecializedPipeline(const VkPipelineKey& key); + PipelineData* GetGeneralizedPipeline(const VkPipelineKey& key); + + VkPipelineKey GetFragmentShaderKey(const VkPipelineKey& key, bool isUberShader); + void PrecompileFragmentShaderLibrary(const VkPipelineKey& key, bool isUberShader); VulkanPipeline* GetVertexInputLibrary(int vertexFormat, int drawType, bool useLevelMesh, int userUniformSize); VulkanPipeline* GetVertexShaderLibrary(const VkPipelineKey& key, bool isUberShader); @@ -100,7 +106,7 @@ private: std::unique_ptr CreateVertexInputLibrary(int vertexFormat, int drawType, bool useLevelMesh, int userUniformSize); std::unique_ptr CreateVertexShaderLibrary(const VkPipelineKey& key, bool isUberShader); - std::unique_ptr CreateFragmentShaderLibrary(const VkPipelineKey& key, bool isUberShader); + std::unique_ptr CreateFragmentShaderLibrary(const VkPipelineKey& key, bool isUberShader); std::unique_ptr CreateFragmentOutputLibrary(FRenderStyle renderStyle, VkColorComponentFlags colorMask); void AddVertexInputInterface(GraphicsPipelineBuilder& builder, int vertexFormat, int drawType); @@ -112,6 +118,7 @@ private: VulkanRenderDevice* fb = nullptr; VkRenderPassKey PassKey; std::unique_ptr RenderPasses[8]; + std::map GeneralizedPipelines; std::map SpecializedPipelines; @@ -159,10 +166,17 @@ public: VulkanPipeline* GetZMinMaxPipeline0(VkSampleCountFlagBits samples) { return ZMinMax.Pipeline[samples > 1 ? 1 : 0].get(); } VulkanPipeline* GetZMinMaxPipeline1() { return ZMinMax.Pipeline[2].get(); } + void ProcessMainThreadTasks(); + void RunOnWorkerThread(std::function task); + void RunOnMainThread(std::function task); + private: void CreateLightTilesPipeline(); void CreateZMinMaxPipeline(); + void StopWorkerThread(); + void WorkerThreadMain(); + VulkanRenderDevice* fb = nullptr; std::map> RenderPassSetup; @@ -186,4 +200,14 @@ private: FString CacheFilename; std::unique_ptr PipelineCache; + + struct + { + std::thread Thread; + std::mutex Mutex; + std::condition_variable CondVar; + bool StopFlag = false; + std::vector> WorkerTasks; + std::vector> MainTasks; + } Worker; }; diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 8a2cf4cd8..9e833bb21 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -360,7 +360,7 @@ void VkShaderManager::BuildLayoutBlock(FString &layoutBlock, bool isFrag, const } } -void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defines, bool isFrag, const VkShaderKey& key, const UserShaderDesc *shader) +void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defines, bool isFrag, const VkShaderKey& key, const UserShaderDesc *shader, bool isUberShader) { if (fb->IsRayQueryEnabled()) { @@ -388,8 +388,8 @@ void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defin definesBlock << LoadPrivateShaderLump("shaders/shaderkey.glsl").GetChars() << "\n"; - // What is this define about? Why is it needed? - definesBlock << "#define UBERSHADERS\n"; + if (isUberShader) + definesBlock << "#define UBERSHADER\n"; // Controls layout and has to be defines: @@ -471,7 +471,7 @@ void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defin std::unique_ptr VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key, const UserShaderDesc *shader, bool isUberShader) { FString definesBlock; - BuildDefinesBlock(definesBlock, defines, false, key, shader); + BuildDefinesBlock(definesBlock, defines, false, key, shader, isUberShader); FString layoutBlock; BuildLayoutBlock(layoutBlock, false, key, shader, isUberShader); @@ -504,7 +504,7 @@ std::unique_ptr VkShaderManager::LoadVertShader(FString shadername 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 UserShaderDesc *shader, bool isUberShader) { FString definesBlock; - BuildDefinesBlock(definesBlock, defines, true, key, shader); + BuildDefinesBlock(definesBlock, defines, true, key, shader, isUberShader); FString layoutBlock; BuildLayoutBlock(layoutBlock, true, key, shader, isUberShader); diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index 29ab2b45e..b50f2af4a 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -190,7 +190,7 @@ private: FString LoadPrivateShaderLump(const char *lumpname); void BuildLayoutBlock(FString &definesBlock, bool isFrag, const VkShaderKey& key, const UserShaderDesc *shader, bool isUberShader); - void BuildDefinesBlock(FString &definesBlock, const char *defines, bool isFrag, const VkShaderKey& key, const UserShaderDesc *shader); + void BuildDefinesBlock(FString &definesBlock, const char *defines, bool isFrag, const VkShaderKey& key, const UserShaderDesc *shader, bool isUberShader); VulkanRenderDevice* fb = nullptr; diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index 8538311e3..9123e0db2 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -538,6 +538,8 @@ void VulkanRenderDevice::BeginFrame() } hwtexturecount = mTextureManager->GetHWTextureCount(); + GetRenderPassManager()->ProcessMainThreadTasks(); + if (levelMeshChanged) { levelMeshChanged = false; diff --git a/wadsrc/static/shaders/scene/lightmodel_normal.glsl b/wadsrc/static/shaders/scene/lightmodel_normal.glsl index 33feaae65..1c7be4084 100644 --- a/wadsrc/static/shaders/scene/lightmodel_normal.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_normal.glsl @@ -55,6 +55,8 @@ { vec4 dynlight = uDynLightColor; vec3 normal = material.Normal; + + #ifndef UBERSHADER #ifdef SHADE_VERTEX dynlight.rgb += vLightColor; @@ -79,6 +81,8 @@ } } #endif + + #endif vec3 frag; @@ -96,6 +100,7 @@ frag = material.Base.rgb * (color + desaturate(dynlight).rgb); } + #ifndef UBERSHADER #ifndef SHADE_VERTEX if (uLightIndex >= 0) { @@ -114,6 +119,7 @@ } } #endif + #endif return frag; } diff --git a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl index 20f1679bb..5cca96e3c 100644 --- a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl @@ -104,6 +104,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight) vec3 Lo = uDynLightColor.rgb; +#ifndef UBERSHADER if (uLightIndex >= 0) { ivec4 lightRange = getLightRange(); @@ -125,6 +126,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight) } } } +#endif // Treat the ambient sector light as if it is a light source next to the wall { diff --git a/wadsrc/static/shaders/scene/lightmodel_specular.glsl b/wadsrc/static/shaders/scene/lightmodel_specular.glsl index 6aa0ed65b..9e264dcb4 100644 --- a/wadsrc/static/shaders/scene/lightmodel_specular.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_specular.glsl @@ -44,6 +44,7 @@ vec3 ProcessMaterialLight(Material material, vec3 color) vec3 normal = material.Normal; vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz); +#ifndef UBERSHADER if (uLightIndex >= 0) { ivec4 lightRange = getLightRange(); @@ -68,6 +69,7 @@ vec3 ProcessMaterialLight(Material material, vec3 color) } } } +#endif if (LIGHT_BLEND_CLAMPED) { @@ -90,6 +92,7 @@ vec3 ProcessMaterialLight(Material material, vec3 color) vec3 frag = material.Base.rgb * dynlight.rgb + material.Specular * specular.rgb; +#ifndef UBERSHADER if (uLightIndex >= 0) { ivec4 lightRange = getLightRange(); @@ -108,6 +111,7 @@ vec3 ProcessMaterialLight(Material material, vec3 color) frag = clamp(frag + desaturate(addlight).rgb, 0.0, 1.0); } } +#endif return frag; }