From ff6d412237d7c268bd29a9f5a67beff40c35df16 Mon Sep 17 00:00:00 2001 From: dpjudas Date: Tue, 4 Apr 2023 01:00:08 +0200 Subject: [PATCH] Add VkShaderKey and start preparing VkShaderManager to be able to handle a lot more shader permutations --- .../vulkan/renderer/vk_renderpass.cpp | 10 +--- .../rendering/vulkan/renderer/vk_renderpass.h | 47 +++++++++++-------- .../vulkan/renderer/vk_renderstate.cpp | 16 +++---- .../rendering/vulkan/shaders/vk_shader.cpp | 12 +++++ .../rendering/vulkan/shaders/vk_shader.h | 34 +++++++++++++- 5 files changed, 81 insertions(+), 38 deletions(-) diff --git a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp index e445723d09..3f70db6d65 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp @@ -245,15 +245,7 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli GraphicsPipelineBuilder builder; builder.Cache(fb->GetRenderPassManager()->GetCache()); - VkShaderProgram *program; - if (key.SpecialEffect != EFF_NONE) - { - program = fb->GetShaderManager()->GetEffect(key.SpecialEffect, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); - } - else - { - program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); - } + VkShaderProgram *program = fb->GetShaderManager()->Get(key.ShaderKey, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS); builder.AddVertexShader(program->vert.get()); builder.AddFragmentShader(program->frag.get()); diff --git a/src/common/rendering/vulkan/renderer/vk_renderpass.h b/src/common/rendering/vulkan/renderer/vk_renderpass.h index 25fd7d186c..23b5f4dbfa 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderpass.h +++ b/src/common/rendering/vulkan/renderer/vk_renderpass.h @@ -6,6 +6,7 @@ #include "hwrenderer/data/buffers.h" #include "hwrenderer/postprocessing/hw_postprocess.h" #include "hw_renderstate.h" +#include "common/rendering/vulkan/shaders/vk_shader.h" #include #include @@ -17,21 +18,29 @@ class VkPipelineKey { public: FRenderStyle RenderStyle; - int SpecialEffect; - int EffectState; - int AlphaTest; - int DepthWrite; - int DepthTest; - int DepthFunc; - int DepthClamp; - int DepthBias; - int StencilTest; - int StencilPassOp; - int ColorMask; - int CullMode; - int VertexFormat; - int DrawType; - int NumTextureLayers; + + union + { + struct + { + uint32_t DrawType : 3; + uint32_t CullMode : 2; + uint32_t ColorMask : 4; + uint32_t DepthWrite : 1; + uint32_t DepthTest : 1; + uint32_t DepthClamp : 1; + uint32_t DepthBias : 1; + uint32_t DepthFunc : 2; + uint32_t StencilTest : 1; + uint32_t StencilPassOp : 2; + uint32_t Unused : 14; + }; + uint32_t AsDWORD = 0; + }; + + VkShaderKey ShaderKey; + int VertexFormat = 0; + int NumTextureLayers = 0; bool operator<(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) < 0; } bool operator==(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) == 0; } @@ -41,10 +50,10 @@ public: class VkRenderPassKey { public: - int DepthStencil; - int Samples; - int DrawBuffers; - VkFormat DrawBufferFormat; + int DepthStencil = 0; + int Samples = 0; + int DrawBuffers = 0; + VkFormat DrawBufferFormat = VK_FORMAT_UNDEFINED; bool operator<(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) < 0; } bool operator==(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) == 0; } diff --git a/src/common/rendering/vulkan/renderer/vk_renderstate.cpp b/src/common/rendering/vulkan/renderer/vk_renderstate.cpp index 76bd35cb09..21b9e7ab44 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/renderer/vk_renderstate.cpp @@ -234,18 +234,18 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.NumTextureLayers = max(pipelineKey.NumTextureLayers, SHADER_MIN_REQUIRED_TEXTURE_LAYERS);// Always force minimum 8 textures as the shader requires it if (mSpecialEffect > EFF_NONE) { - pipelineKey.SpecialEffect = mSpecialEffect; - pipelineKey.EffectState = 0; - pipelineKey.AlphaTest = false; + pipelineKey.ShaderKey.SpecialEffect = mSpecialEffect; + pipelineKey.ShaderKey.EffectState = 0; + pipelineKey.ShaderKey.AlphaTest = false; } else { int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0); - pipelineKey.SpecialEffect = EFF_NONE; - pipelineKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture; - if (r_skipmats && pipelineKey.EffectState >= 3 && pipelineKey.EffectState <= 4) - pipelineKey.EffectState = 0; - pipelineKey.AlphaTest = mAlphaThreshold >= 0.f; + pipelineKey.ShaderKey.SpecialEffect = EFF_NONE; + pipelineKey.ShaderKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture; + if (r_skipmats && pipelineKey.ShaderKey.EffectState >= 3 && pipelineKey.ShaderKey.EffectState <= 4) + pipelineKey.ShaderKey.EffectState = 0; + pipelineKey.ShaderKey.AlphaTest = mAlphaThreshold >= 0.f; } // Is this the one we already have? diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 27a3a5fe48..c4ce837f11 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -128,6 +128,18 @@ void VkShaderManager::Deinit() RemoveVkPPShader(PPShaders.back()); } +VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key, EPassType passType) +{ + if (key.SpecialEffect != EFF_NONE) + { + return GetEffect(key.SpecialEffect, passType); + } + else + { + return Get(key.EffectState, key.AlphaTest, passType); + } +} + VkShaderProgram *VkShaderManager::GetEffect(int effect, EPassType passType) { if (compileIndex == -1 && effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[passType][effect].frag) diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index 37d45fc646..a4b15edf93 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -58,6 +58,33 @@ struct PushConstants int padding1, padding2, padding3; }; +class VkShaderKey +{ +public: + union + { + struct + { + uint32_t AlphaTest : 1; + uint32_t Simple2D : 1; // uFogEnabled == -3 + uint32_t TextureMode : 3; // uTextureMode & 0xffff + uint32_t ClampY : 1; // uTextureMode & TEXF_ClampY + uint32_t Brightmap : 1; // uTextureMode & TEXF_Brightmap + uint32_t Detailmap : 1; // uTextureMode & TEXF_Detailmap + uint32_t Glowmap : 1; // uTextureMode & TEXF_Glowmap + uint32_t Unused : 23; + }; + uint32_t AsDWORD = 0; + }; + + int SpecialEffect = 0; + int EffectState = 0; + + bool operator<(const VkShaderKey& other) const { return memcmp(this, &other, sizeof(VkShaderKey)) < 0; } + bool operator==(const VkShaderKey& other) const { return memcmp(this, &other, sizeof(VkShaderKey)) == 0; } + bool operator!=(const VkShaderKey& other) const { return memcmp(this, &other, sizeof(VkShaderKey)) != 0; } +}; + class VkShaderProgram { public: @@ -73,8 +100,8 @@ public: void Deinit(); - VkShaderProgram *GetEffect(int effect, EPassType passType); - VkShaderProgram *Get(unsigned int eff, bool alphateston, EPassType passType); + VkShaderProgram* Get(const VkShaderKey& key, EPassType passType); + bool CompileNextShader(); VkPPShader* GetVkShader(PPShader* shader); @@ -83,6 +110,9 @@ public: void RemoveVkPPShader(VkPPShader* shader); private: + VkShaderProgram* GetEffect(int effect, EPassType passType); + VkShaderProgram* Get(unsigned int eff, bool alphateston, EPassType passType); + std::unique_ptr LoadVertShader(FString shadername, const char *vert_lump, const char *defines); std::unique_ptr LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *lightmodel_lump, const char *defines, bool alphatest, bool gbufferpass);