From 14a57bd12c255e42957ff08761521b54b1c8e42a Mon Sep 17 00:00:00 2001 From: gameblabla <gameblabla@protonmail.com> Date: Tue, 5 Mar 2024 10:54:50 +0100 Subject: [PATCH] spirv: fix multisampled image fetch Fixes Vulkan shader compiler crash in Fire Emblem Engage. Original fix by @liamwhite --- backend/spirv/emit_spirv_image.cpp | 4 ++++ backend/spirv/spirv_emit_context.cpp | 5 +++-- ir_opt/texture_pass.cpp | 8 ++++++++ shader_info.h | 1 + 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/backend/spirv/emit_spirv_image.cpp b/backend/spirv/emit_spirv_image.cpp index 68ea763..3f679dc 100644 --- a/backend/spirv/emit_spirv_image.cpp +++ b/backend/spirv/emit_spirv_image.cpp @@ -437,6 +437,10 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c if (info.type == TextureType::Buffer) { lod = Id{}; } + if (Sirit::ValidId(ms)) { + // This image is multisampled, lod must be implicit + lod = Id{}; + } const ImageOperands operands(offset, lod, ms); return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); diff --git a/backend/spirv/spirv_emit_context.cpp b/backend/spirv/spirv_emit_context.cpp index ac04b6c..3e53b11 100644 --- a/backend/spirv/spirv_emit_context.cpp +++ b/backend/spirv/spirv_emit_context.cpp @@ -29,6 +29,7 @@ Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { const spv::ImageFormat format{spv::ImageFormat::Unknown}; const Id type{ctx.F32[1]}; const bool depth{desc.is_depth}; + const bool ms{desc.is_multisample}; switch (desc.type) { case TextureType::Color1D: return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format); @@ -36,9 +37,9 @@ Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format); case TextureType::Color2D: case TextureType::Color2DRect: - return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, false, 1, format); + return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, ms, 1, format); case TextureType::ColorArray2D: - return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, false, 1, format); + return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, ms, 1, format); case TextureType::Color3D: return ctx.TypeImage(type, spv::Dim::Dim3D, depth, false, false, 1, format); case TextureType::ColorCube: diff --git a/ir_opt/texture_pass.cpp b/ir_opt/texture_pass.cpp index 9d081aa..6b88560 100644 --- a/ir_opt/texture_pass.cpp +++ b/ir_opt/texture_pass.cpp @@ -525,6 +525,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo const auto& cbuf{texture_inst.cbuf}; auto flags{inst->Flags<IR::TextureInstInfo>()}; + bool is_multisample{false}; switch (inst->GetOpcode()) { case IR::Opcode::ImageQueryDimensions: flags.type.Assign(ReadTextureType(env, cbuf)); @@ -539,6 +540,12 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo } break; case IR::Opcode::ImageFetch: + if (flags.type == TextureType::Color2D || flags.type == TextureType::Color2DRect || + flags.type == TextureType::ColorArray2D) { + is_multisample = !inst->Arg(4).IsEmpty(); + } else { + inst->SetArg(4, IR::U32{}); + } if (flags.type != TextureType::Color1D) { break; } @@ -614,6 +621,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo index = descriptors.Add(TextureDescriptor{ .type = flags.type, .is_depth = flags.is_depth != 0, + .is_multisample = is_multisample, .has_secondary = cbuf.has_secondary, .cbuf_index = cbuf.index, .cbuf_offset = cbuf.offset, diff --git a/shader_info.h b/shader_info.h index 7744514..dfadcc2 100644 --- a/shader_info.h +++ b/shader_info.h @@ -109,6 +109,7 @@ using ImageBufferDescriptors = boost::container::small_vector<ImageBufferDescrip struct TextureDescriptor { TextureType type; bool is_depth; + bool is_multisample; bool has_secondary; u32 cbuf_index; u32 cbuf_offset;