From df088c6442906020aaff568e22ea30ed87043a21 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sat, 29 Nov 2025 00:30:09 -0400 Subject: [PATCH] [Re-introduced] Color output handling in SPIR-V emission --- .../spirv/emit_spirv_context_get_set.cpp | 19 ++++++++++++++++-- .../backend/spirv/spirv_emit_context.cpp | 14 ++++++++++++- .../backend/spirv/spirv_emit_context.h | 4 ++++ src/shader_recompiler/runtime_info.h | 4 ++++ .../renderer_vulkan/vk_pipeline_cache.cpp | 20 +++++++++++++++++++ 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 1de5709394..543af5db83 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -491,9 +491,24 @@ void EmitSetPatch(EmitContext& ctx, IR::Patch patch, Id value) { } void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { + const AttributeType output_type{ctx.runtime_info.color_output_types[index]}; + Id pointer_type{ctx.output_f32}; + Id store_value{value}; + switch (output_type) { + case AttributeType::SignedInt: + pointer_type = ctx.output_s32; + store_value = ctx.OpBitcast(ctx.S32[1], value); + break; + case AttributeType::UnsignedInt: + pointer_type = ctx.output_u32; + store_value = ctx.OpBitcast(ctx.U32[1], value); + break; + default: + break; + } const Id component_id{ctx.Const(component)}; - const Id pointer{ctx.OpAccessChain(ctx.output_f32, ctx.frag_color.at(index), component_id)}; - ctx.OpStore(pointer, value); + const Id pointer{ctx.OpAccessChain(pointer_type, ctx.frag_color.at(index), component_id)}; + ctx.OpStore(pointer, store_value); } void EmitSetSampleMask(EmitContext& ctx, Id value) { diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 9102d5510f..8d4aff315a 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -563,6 +563,7 @@ void EmitContext::DefineCommonTypes(const Info& info) { output_f32 = Name(TypePointer(spv::StorageClass::Output, F32[1]), "output_f32"); output_u32 = Name(TypePointer(spv::StorageClass::Output, U32[1]), "output_u32"); + output_s32 = Name(TypePointer(spv::StorageClass::Output, S32[1]), "output_s32"); if (info.uses_int8 && profile.support_int8) { AddCapability(spv::Capability::Int8); @@ -1699,7 +1700,18 @@ void EmitContext::DefineOutputs(const IR::Program& program) { if (!info.stores_frag_color[index] && !profile.need_declared_frag_colors) { continue; } - frag_color[index] = DefineOutput(*this, F32[4], std::nullopt); + const AttributeType output_type{runtime_info.color_output_types[index]}; + const Id vec_type = [&, output_type]() -> Id { + switch (output_type) { + case AttributeType::SignedInt: + return S32[4]; + case AttributeType::UnsignedInt: + return U32[4]; + default: + return F32[4]; + } + }(); + frag_color[index] = DefineOutput(*this, vec_type, std::nullopt); Decorate(frag_color[index], spv::Decoration::Location, index); Name(frag_color[index], fmt::format("frag_color{}", index)); } diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 7c4777a973..1a252bf9f0 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -246,6 +249,7 @@ public: Id output_f32{}; Id output_u32{}; + Id output_s32{}; Id image_buffer_type{}; Id image_u32{}; diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index dc54d932a6..22dc095f1e 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -80,6 +83,7 @@ struct TransformFeedbackVarying { struct RuntimeInfo { std::array generic_input_types{}; + std::array color_output_types{}; VaryingState previous_stage_stores; std::map previous_stage_legacy_stores_mapping; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index aea1cd827e..ce35a7be1d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -36,6 +36,7 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" +#include "video_core/surface.h" #include "video_core/shader_cache.h" #include "video_core/shader_environment.h" #include "video_core/shader_notify.h" @@ -105,6 +106,21 @@ Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp compariso return {}; } +Shader::AttributeType RenderTargetAttributeType(Tegra::RenderTargetFormat format) { + if (format == Tegra::RenderTargetFormat::NONE) { + return Shader::AttributeType::Float; + } + const auto pixel_format{ + VideoCore::Surface::PixelFormatFromRenderTargetFormat(format)}; + if (!VideoCore::Surface::IsPixelFormatInteger(pixel_format)) { + return Shader::AttributeType::Float; + } + if (VideoCore::Surface::IsPixelFormatSignedInteger(pixel_format)) { + return Shader::AttributeType::SignedInt; + } + return Shader::AttributeType::UnsignedInt; +} + VkShaderStageFlagBits StageToVkStage(Shader::Stage stage) { switch (stage) { case Shader::Stage::VertexA: @@ -249,6 +265,10 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span program info.alpha_test_func = MaxwellToCompareFunction( key.state.UnpackComparisonOp(key.state.alpha_test_func.Value())); info.alpha_test_reference = std::bit_cast(key.state.alpha_test_ref); + for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { + const auto format = static_cast(key.state.color_formats[index]); + info.color_output_types[index] = RenderTargetAttributeType(format); + } break; default: break;