diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp index f293d47f8..de4c790fc 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp @@ -309,7 +309,7 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli if (program->frag) builder.AddFragmentShader(program->frag.get()); - const VkVertexFormat &vfmt = *fb->GetRenderPassManager()->GetVertexFormat(key.VertexFormat); + const VkVertexFormat &vfmt = *fb->GetRenderPassManager()->GetVertexFormat(key.ShaderKey.VertexFormat); for (int i = 0; i < vfmt.BufferStrides.size(); i++) builder.AddVertexBufferBinding(i, vfmt.BufferStrides[i]); @@ -325,20 +325,10 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli VK_FORMAT_R32_SINT }; - bool inputLocations[VATTR_MAX] = {}; - for (size_t i = 0; i < vfmt.Attrs.size(); i++) { const auto &attr = vfmt.Attrs[i]; builder.AddVertexAttribute(attr.location, attr.binding, vkfmts[attr.format], attr.offset); - inputLocations[attr.location] = true; - } - - // Vulkan requires an attribute binding for each location specified in the shader - for (int i = 0; i < VATTR_MAX; i++) - { - if (!inputLocations[i]) - builder.AddVertexAttribute(i, 0, i != 8 ? VK_FORMAT_R32G32B32_SFLOAT : VK_FORMAT_R8G8B8A8_UINT, 0); } builder.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT); diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.h b/src/common/rendering/vulkan/pipelines/vk_renderpass.h index 433ba8a98..b1e114a92 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.h +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.h @@ -40,13 +40,13 @@ class VkPipelineKey uint64_t AsQWORD = 0; }; - int VertexFormat = 0; - int Padding0 = 0; + int Padding1 = 0; + int Padding2 = 0; VkShaderKey ShaderKey; FRenderStyle RenderStyle; - int Padding1 = 0; // for 64 bit alignment + int Padding3 = 0; // for 64 bit alignment 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; } @@ -54,8 +54,8 @@ class VkPipelineKey }; static_assert(sizeof(FRenderStyle) == 4, "sizeof(FRenderStyle) is not its expected size!"); -static_assert(sizeof(VkShaderKey) == 16, "sizeof(VkShaderKey) is not its expected size!"); -static_assert(sizeof(VkPipelineKey) == 16 + 16 + 8, "sizeof(VkPipelineKey) is not its expected size!"); // If this assert fails, the flags union no longer adds up to 64 bits. Or there are gaps in the class so the memcmp doesn't work. +static_assert(sizeof(VkShaderKey) == 24, "sizeof(VkShaderKey) is not its expected size!"); +static_assert(sizeof(VkPipelineKey) == 16 + 24 + 8, "sizeof(VkPipelineKey) is not its expected size!"); // If this assert fails, the flags union no longer adds up to 64 bits. Or there are gaps in the class so the memcmp doesn't work. class VkRenderPassKey { diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 0e8a58043..686e2f27d 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -23,6 +23,7 @@ #include "vk_shader.h" #include "vk_ppshader.h" #include "vulkan/vk_renderdevice.h" +#include "vulkan/pipelines/vk_renderpass.h" #include #include "hw_shaderpatcher.h" #include "filesystem.h" @@ -224,7 +225,17 @@ static std::vector fragShaderOutputs {"FragNormal", "", UniformType::Vec4, FieldCondition::GBUFFER_PASS}, //2 }; -void AddFields(FString &layoutBlock, int &index, bool is_in, const std::vector &fields) +static void AddVertexInFields(VulkanRenderDevice* fb, FString& layoutBlock, const VkShaderKey& key) +{ + const VkVertexFormat& vfmt = *fb->GetRenderPassManager()->GetVertexFormat(key.VertexFormat); + for (const FVertexBufferAttribute& attr : vfmt.Attrs) + { + const VaryingFieldDesc& desc = vertexShaderInputs[attr.location]; + layoutBlock.AppendFormat("layout(location = %d) %s %s %s %s;\n", attr.location, desc.Property.GetChars(), "in", GetTypeStr(desc.Type), desc.Name.GetChars()); + } +} + +static void AddFields(FString &layoutBlock, int &index, bool is_in, const std::vector &fields) { for(auto &field : fields) { @@ -233,7 +244,7 @@ void AddFields(FString &layoutBlock, int &index, bool is_in, const std::vector &fields, const VkShaderKey& key, bool hasClipDistance) +static void AddBuiltinFields(FString &layoutBlock, int &index, bool is_in, const std::vector &fields, const VkShaderKey& key, bool hasClipDistance) { for(auto &field : fields) { @@ -294,8 +305,7 @@ void VkShaderManager::BuildLayoutBlock(FString &layoutBlock, bool isFrag, const if(!isFrag) { - int index = 0; - AddFields(layoutBlock, index, true, vertexShaderInputs); + AddVertexInFields(fb, layoutBlock, key); } { @@ -421,6 +431,19 @@ void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defin if (key.UseSpriteCenter) definesBlock << "#define USE_SPRITE_CENTER\n"; definesBlock << ((key.Simple2D) ? "#define uFogEnabled -3\n" : "#define uFogEnabled 0\n"); + + // Setup fake variables for the 'in' attributes that aren't actually available because the garbage shader code thinks they exist + // God I hate this engine... :( + std::vector definedFields(vertexShaderInputs.size()); + bool hasNormal = false; + const VkVertexFormat& vfmt = *fb->GetRenderPassManager()->GetVertexFormat(key.VertexFormat); + for (const FVertexBufferAttribute& attr : vfmt.Attrs) + definedFields[attr.location] = true; + for (size_t i = 0; i < vertexShaderInputs.size(); i++) + { + if (!definedFields[i]) + definesBlock << "#define " << vertexShaderInputs[i].Name << " " << GetTypeStr(vertexShaderInputs[i].Type) << "(0)\n"; + } } 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) diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index cb8d2c501..1accd8373 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -118,13 +118,15 @@ class VkShaderKey int SpecialEffect = 0; int EffectState = 0; + int VertexFormat = 0; + int Padding = 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; } }; -static_assert(sizeof(VkShaderKey) == 16, "sizeof(VkShaderKey) is not its expected size!"); // If this assert fails, the flags union no longer adds up to 64 bits. Or there are gaps in the class so the memcmp doesn't work. +static_assert(sizeof(VkShaderKey) == 24, "sizeof(VkShaderKey) is not its expected size!"); // If this assert fails, the flags union no longer adds up to 64 bits. Or there are gaps in the class so the memcmp doesn't work. class VkShaderProgram { diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index fc7e3f700..e27c8d33a 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -686,9 +686,9 @@ int VulkanRenderDevice::GetLevelMeshPipelineID(const MeshApplyData& applyData, c VkPipelineKey pipelineKey; pipelineKey.DrawType = DT_Triangles; - pipelineKey.VertexFormat = levelVertexFormatIndex; pipelineKey.RenderStyle = applyData.RenderStyle; pipelineKey.DepthFunc = applyData.DepthFunc; + pipelineKey.ShaderKey.VertexFormat = levelVertexFormatIndex; if (applyData.SpecialEffect > EFF_NONE) { pipelineKey.ShaderKey.SpecialEffect = applyData.SpecialEffect; diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index e80f7d1c7..52a8e4e38 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -249,7 +249,6 @@ void VkRenderState::ApplyRenderPass(int dt) VkPipelineKey pipelineKey; pipelineKey.DrawType = dt; pipelineKey.DrawLine = mDrawLine || mWireframe; - pipelineKey.VertexFormat = mVertexBuffer ? static_cast(mVertexBuffer)->VertexFormat : mRSBuffers->Flatbuffer.VertexFormat; pipelineKey.RenderStyle = mRenderStyle; pipelineKey.DepthTest = mDepthTest && !mWireframe; pipelineKey.DepthWrite = mDepthTest && !mWireframe && mDepthWrite; @@ -260,6 +259,7 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.StencilPassOp = mStencilOp; pipelineKey.ColorMask = mColorMask; pipelineKey.CullMode = mCullMode; + pipelineKey.ShaderKey.VertexFormat = mVertexBuffer ? static_cast(mVertexBuffer)->VertexFormat : mRSBuffers->Flatbuffer.VertexFormat; if (mSpecialEffect > EFF_NONE) { pipelineKey.ShaderKey.SpecialEffect = mSpecialEffect;