shader_recompiler: Improve shader exports accuracy (part 1) (#3447)

* video_core: support for RT layer outputs

- support for RT layer outputs
- refactor for handling of export attributes
- move output->attribute mapping to a separate header

* export: Rework render target exports

- Centralize all code related to MRT exports into a single function to make it easier to follow
- Apply swizzle to output RGBA colors instead of the render target channel.
  This fixes swizzles on formats with < 4 channels

For example with render target format R8_UNORM and COMP_SWAP ALT_REV the previous code would output

frag_color.a = color.r;

instead of

frag_color.r = color.a;

which would result in incorrect output in some cases

* vk_pipeline_cache: Apply swizzle to write masks

---------

Co-authored-by: polyproxy <47796739+polybiusproxy@users.noreply.github.com>
This commit is contained in:
TheTurtle
2025-08-24 00:39:59 +03:00
committed by GitHub
parent d42f4fcc4f
commit 6dd2b3090c
17 changed files with 289 additions and 275 deletions

View File

@@ -4,6 +4,7 @@
#include "common/assert.h"
#include "shader_recompiler/ir/ir_emitter.h"
#include "shader_recompiler/ir/opcodes.h"
#include "shader_recompiler/ir/position.h"
#include "shader_recompiler/ir/program.h"
#include "shader_recompiler/ir/reg.h"
#include "shader_recompiler/recompiler.h"
@@ -142,11 +143,12 @@ void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtim
ASSERT(it != info.gs_copy_data.attr_map.cend());
const auto& [attr, comp] = it->second;
inst.ReplaceOpcode(IR::Opcode::SetAttribute);
inst.ClearArgs();
inst.SetArg(0, IR::Value{attr});
inst.SetArg(1, data);
inst.SetArg(2, ir.Imm32(comp));
inst.Invalidate();
if (IsPosition(attr)) {
ExportPosition(ir, runtime_info.gs_info, attr, comp, data);
} else {
ir.SetAttribute(attr, data, comp);
}
break;
}
default:

View File

@@ -160,6 +160,10 @@ void CollectShaderInfoPass(IR::Program& program, const Profile& profile) {
}
}
if (info.stores.GetAny(IR::Attribute::RenderTargetId)) {
info.has_layer_output = true;
}
// In case Flatbuf has not already been bound by IR and is needed
// to query buffer sizes, bind it now.
if (!profile.supports_robust_buffer_access && !info.uses_dma) {

View File

@@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "shader_recompiler/ir/ir_emitter.h"
#include "shader_recompiler/runtime_info.h"
namespace Shader::IR {
/// Maps special position export to builtin attribute stores
inline void ExportPosition(IREmitter& ir, const auto& stage, Attribute attribute, u32 comp,
const IR::F32& value) {
if (attribute == Attribute::Position0) {
ir.SetAttribute(attribute, value, comp);
return;
}
const u32 index = u32(attribute) - u32(Attribute::Position1);
const auto output = stage.outputs[index][comp];
switch (output) {
case Output::ClipDist0:
case Output::ClipDist1:
case Output::ClipDist2:
case Output::ClipDist3:
case Output::ClipDist4:
case Output::ClipDist5:
case Output::ClipDist6:
case Output::ClipDist7: {
const u32 index = u32(output) - u32(Output::ClipDist0);
ir.SetAttribute(IR::Attribute::ClipDistance, value, index);
break;
}
case Output::CullDist0:
case Output::CullDist1:
case Output::CullDist2:
case Output::CullDist3:
case Output::CullDist4:
case Output::CullDist5:
case Output::CullDist6:
case Output::CullDist7: {
const u32 index = u32(output) - u32(Output::CullDist0);
ir.SetAttribute(IR::Attribute::CullDistance, value, index);
break;
}
case Output::GsMrtIndex:
ir.SetAttribute(IR::Attribute::RenderTargetId, value);
break;
default:
UNREACHABLE_MSG("Unhandled output {} on attribute {}", u32(output), u32(attribute));
}
}
} // namespace Shader::IR