diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 4c3e101433..d8616f9ebf 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -1654,10 +1654,48 @@ void EmitContext::DefineOutputs(const IR::Program& program) { } break; case Stage::Fragment: - for (u32 index = 0; index < 8; ++index) { + for (u32 index = 0; index < 8; ++index) { if (!info.stores_frag_color[index] && !profile.need_declared_frag_colors) { continue; } + + // MoltenVK/Metal: Use integer output type for integer render targets + // Metal requires fragment shader outputs to match render target formats. + // On other platforms, always use F32[4] (float vec4) as usual. + Id output_type = F32[4]; // Default to float + if (runtime_info.is_moltenvk && index < runtime_info.color_formats.size()) { + const auto& format = runtime_info.color_formats[index]; + // Check if the render target format is an integer format + const bool is_integer_format = ( + format == PixelFormat::R8_UINT || + format == PixelFormat::R8_SINT || + format == PixelFormat::R16_UINT || + format == PixelFormat::R16_SINT || + format == PixelFormat::R32_UINT || + format == PixelFormat::R32_SINT || + format == PixelFormat::R8G8_UINT || + format == PixelFormat::R8G8_SINT || + format == PixelFormat::R16G16_UINT || + format == PixelFormat::R16G16_SINT || + format == PixelFormat::R32G32_UINT || + format == PixelFormat::R32G32_SINT || + format == PixelFormat::R8G8B8A8_UINT || + format == PixelFormat::R8G8B8A8_SINT || + format == PixelFormat::R16G16B16A16_UINT || + format == PixelFormat::R16G16B16A16_SINT || + format == PixelFormat::R32G32B32A32_UINT || + format == PixelFormat::R32G32B32A32_SINT || + format == PixelFormat::A8B8G8R8_UINT || + format == PixelFormat::A8B8G8R8_SINT + ); + if (is_integer_format) { + output_type = U32[4]; // Use unsigned int vec4 for integer formats + } + } + frag_color[index] = DefineOutput(*this, output_type, std::nullopt); + Decorate(frag_color[index], spv::Decoration::Location, index); + Name(frag_color[index], fmt::format("frag_color{}", index)); + } frag_color[index] = DefineOutput(*this, F32[4], std::nullopt); Decorate(frag_color[index], spv::Decoration::Location, index); Name(frag_color[index], fmt::format("frag_color{}", index));