152 lines
5.4 KiB
C#
152 lines
5.4 KiB
C#
|
|
using Ryujinx.Common.Logging;
|
|
using Ryujinx.Graphics.GAL;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
{
|
|
static class MvppInjectGate
|
|
{
|
|
private static readonly bool _verbose =
|
|
Environment.GetEnvironmentVariable("RYUJINX_MVPP_INJECTGATE") == "1";
|
|
private static bool _enabled = _verbose || MvppInjectState.Enabled;
|
|
|
|
private const ulong TargetFs = 0x559E30;
|
|
private const int MaxFullLogged = 40;
|
|
|
|
private static long _total;
|
|
private static long _candidates;
|
|
private static long _nearMiss;
|
|
private static int _fullLogged;
|
|
private static long _summaryMs;
|
|
private static readonly HashSet<(ulong, ulong)> _candidatePairs = new();
|
|
|
|
private static long _relaxedCandidates;
|
|
private static readonly HashSet<(ulong, ulong)> _relaxedPairs = new();
|
|
|
|
public static void OnDraw(GpuChannel channel, ref ThreedClassState state, int count, bool indexed)
|
|
{
|
|
if (!_enabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
OnDrawImpl(channel, ref state, count, indexed);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_enabled = false;
|
|
Logger.Warning?.Print(LogClass.Gpu, $"MVPP inject gate: disabled after unexpected error: {e}");
|
|
}
|
|
}
|
|
|
|
private static void OnDrawImpl(GpuChannel channel, ref ThreedClassState state, int count, bool indexed)
|
|
{
|
|
_total++;
|
|
|
|
bool idx3 = indexed && count == 3;
|
|
bool depthOff = !state.DepthTestEnable;
|
|
bool blendOff = !state.BlendEnable[0];
|
|
|
|
ulong dstAddr = 0;
|
|
Format dstFmt = default;
|
|
int dw = 0, dh = 0;
|
|
bool haveDst = false;
|
|
channel.TextureManager.MvppEnumerateRenderTargets((slot, rt) =>
|
|
{
|
|
if (slot == 0)
|
|
{
|
|
haveDst = true;
|
|
dstAddr = rt.Range.GetSubRange(0).Address;
|
|
dstFmt = rt.Info.FormatInfo.Format;
|
|
dw = rt.Info.Width;
|
|
dh = rt.Info.Height;
|
|
}
|
|
});
|
|
|
|
int texCount = 0;
|
|
ulong srcAddr = 0;
|
|
Format srcFmt = default;
|
|
int sw = 0, sh = 0;
|
|
channel.TextureManager.MvppEnumerateGraphicsInputs(t =>
|
|
{
|
|
if (texCount == 0)
|
|
{
|
|
srcAddr = t.Range.GetSubRange(0).Address;
|
|
srcFmt = t.Info.FormatInfo.Format;
|
|
sw = t.Info.Width;
|
|
sh = t.Info.Height;
|
|
}
|
|
texCount++;
|
|
});
|
|
|
|
ulong sceneAddr = MvppCameraCapture.SceneColorAddress;
|
|
|
|
bool c1 = texCount == 1;
|
|
bool c2 = sceneAddr != 0 && srcAddr == sceneAddr;
|
|
bool c3 = srcFmt == Format.R11G11B10Float;
|
|
bool c4 = haveDst && dstFmt == Format.R11G11B10Float && dw >= 1500 && dw <= 1700;
|
|
bool c5 = sw > 0 && dw > 0 && sw < dw;
|
|
bool c6 = idx3 && depthOff && blendOff;
|
|
|
|
bool gate = c1 && c2 && c3 && c4 && c5 && c6;
|
|
bool relaxed = c1 && c3 && c4 && c5 && c6;
|
|
|
|
ulong vs = (ulong)state.ShaderState[1].Offset;
|
|
ulong fs = (ulong)state.ShaderState[5].Offset;
|
|
|
|
if (relaxed)
|
|
{
|
|
_relaxedCandidates++;
|
|
_relaxedPairs.Add((vs, fs));
|
|
}
|
|
|
|
if (gate)
|
|
{
|
|
_candidates++;
|
|
_candidatePairs.Add((vs, fs));
|
|
|
|
if (_verbose && _fullLogged < MaxFullLogged)
|
|
{
|
|
_fullLogged++;
|
|
Logger.Info?.Print(LogClass.Gpu,
|
|
$"MVPP-INJECT CANDIDATE: src=@0x{srcAddr:X} {srcFmt} {sw}x{sh} dst=@0x{dstAddr:X} {dstFmt} {dw}x{dh} " +
|
|
$"shader=VS@0x{vs:X}/FS@0x{fs:X} fsMatch={(fs == TargetFs)} criteria=1,2,3,4,5,6 PASS");
|
|
}
|
|
}
|
|
else if (c2)
|
|
{
|
|
_nearMiss++;
|
|
if (_verbose && _nearMiss <= 30)
|
|
{
|
|
Logger.Info?.Print(LogClass.Gpu,
|
|
$"MVPP-INJECT near-miss (reads scene, gate fail): src=@0x{srcAddr:X} {srcFmt} {sw}x{sh} " +
|
|
$"dst=@0x{dstAddr:X} {dstFmt} {dw}x{dh} FS@0x{fs:X} | " +
|
|
$"c1={c1} c3={c3} c4={c4} c5={c5} c6={c6} (idx3={idx3} depthOff={depthOff} blendOff={blendOff})");
|
|
}
|
|
}
|
|
|
|
long now = Environment.TickCount64;
|
|
if (_verbose && now - _summaryMs >= 3000)
|
|
{
|
|
_summaryMs = now;
|
|
Logger.Info?.Print(LogClass.Gpu,
|
|
$"MVPP-INJECT SUMMARY: frame={MvppDestProbe.Frame} totalDrawImpl={_total} " +
|
|
$"strict(candidates={_candidates} pairs={_candidatePairs.Count}) " +
|
|
$"RELAXED(candidates={_relaxedCandidates} pairs={_relaxedPairs.Count}) nearMiss={_nearMiss}");
|
|
|
|
if (_relaxedPairs.Count > 1)
|
|
{
|
|
foreach ((ulong pvs, ulong pfs) in _relaxedPairs)
|
|
{
|
|
Logger.Info?.Print(LogClass.Gpu, $"MVPP-INJECT relaxed-pair VS@0x{pvs:X}/FS@0x{pfs:X}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|