From c9fc983482d31f098ca1f7b53c6693777b1aa025 Mon Sep 17 00:00:00 2001 From: Ribbit Date: Mon, 6 Oct 2025 21:11:26 -0700 Subject: [PATCH] [SPIR-V] Auto apply flat interpolation to integer fragment inputs --- .../backend/spirv/spirv_emit_context.cpp | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 4c3e101433..5981722857 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -98,6 +98,48 @@ Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) { throw InvalidArgument("Invalid texture type {}", desc.type); } +bool MatchesVectorType(const VectorTypes& vectors, Id type) { + for (std::size_t components = 1; components <= 4; ++components) { + const Id candidate{vectors[components]}; + if (candidate.value != 0 && candidate.value == type.value) { + return true; + } + } + return false; +} + +bool HasIntegerOrDoubleComponent(const EmitContext& ctx, Id type) { + if (MatchesVectorType(ctx.U32, type) || MatchesVectorType(ctx.S32, type)) { + return true; + } + if (MatchesVectorType(ctx.F64, type)) { + return true; + } + if (ctx.profile.support_int8) { + if ((ctx.U8.value != 0 && ctx.U8.value == type.value) || + (ctx.S8.value != 0 && ctx.S8.value == type.value)) { + return true; + } + } + if (ctx.profile.support_int16) { + if ((ctx.U16.value != 0 && ctx.U16.value == type.value) || + (ctx.S16.value != 0 && ctx.S16.value == type.value)) { + return true; + } + } + if (ctx.profile.support_int64) { + if (ctx.U64.value != 0 && ctx.U64.value == type.value) { + return true; + } + } + return false; +} + +bool RequiresFlatDecoration(const EmitContext& ctx, Id type, spv::StorageClass storage_class) { + return ctx.stage == Stage::Fragment && storage_class == spv::StorageClass::Input && + HasIntegerOrDoubleComponent(ctx, type); +} + Id DefineVariable(EmitContext& ctx, Id type, std::optional builtin, spv::StorageClass storage_class, std::optional initializer = std::nullopt) { const Id pointer_type{ctx.TypePointer(storage_class, type)}; @@ -105,6 +147,9 @@ Id DefineVariable(EmitContext& ctx, Id type, std::optional builtin if (builtin) { ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin); } + if (RequiresFlatDecoration(ctx, type, storage_class)) { + ctx.Decorate(id, spv::Decoration::Flat); + } ctx.interfaces.push_back(id); return id; } @@ -1552,6 +1597,9 @@ void EmitContext::DefineInputs(const IR::Program& program) { if (stage != Stage::Fragment) { continue; } + if (RequiresFlatDecoration(*this, type, spv::StorageClass::Input)) { + continue; + } switch (info.interpolation[index]) { case Interpolation::Smooth: // Default @@ -1678,3 +1726,4 @@ void EmitContext::DefineOutputs(const IR::Program& program) { } } // namespace Shader::Backend::SPIRV +