// SPDX-License-Identifier: MIT
// Copyright (c) 2026 The Roofer Dev - Beast Roofer Edition. Clean-room integration code.
// Built on Ryujinx (MIT). DLSS, DLAA and NIS are NVIDIA technologies; this is integration code only.
using Ryujinx.Common.Logging;
using System;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
///
/// ⛔⛔ MORT PAR LA MESURE, 29/07 AU SOIR -- NE PAS RE-ARMER, NE PAS RE-REGLER. Sonde `HDRTRY` :
/// la passe de scene HDR existe dans **98,9 %** des images 3D, mais la camera n'y est **lisible
/// que dans 36,5 %** des cas. N'autoriser QUE cette passe ferait donc tomber la publication de
/// 83 % a ~37 % : la camera serait AFFAMEE, et une camera manquee fait ecrire zero sur toute
/// l'image. Ce n'est pas un probleme de reglage du filet -- le filet mal dimensionne (voir plus
/// bas) n'etait que le symptome. Le remplacant est , qui ECARTE la pire
/// passe au lieu d'en ELIRE une. Ce fichier est conserve pour la trace, et parce que
/// sert encore a la sonde.
///
/// [SCENEPASS 29/07 SOIR] Capturer la camera sur LA PASSE DE LA SCENE, et non sur la premiere
/// passe 3D venue (RYUJINX_MVPP_SCENEPASS=1, coupe par defaut).
///
/// POURQUOI, ET SUR QUELLE MESURE. capture au PREMIER
/// dessin de l'image qui passe le pre-filtre, puis se tait. Ce pre-filtre reconnait "une passe
/// 3D", pas "LA passe de la scene". Recensement CTXPROBE du 29/07 au soir, run etalon de 3 min,
/// 3 633 lectures et 177 intruses -- du GROS volume, pas trois evenements tires au sort :
///
/// cible couleur branchee a la lecture lectures intruses taux
/// R8G8B8A8Unorm (8 bits, LDR) 1 340 119 8,9 % <- 67 % des intruses
/// aucune (passe profondeur seule) 2 044 52 2,5 %
/// R11G11B10Float (couleur HDR de scene) 230 3 1,3 % <- la vraie passe
/// R32Float 19 3 15,8 %
///
/// La passe 8 bits donne SEPT FOIS plus d'intruses que la couleur HDR et fournit deux tiers du
/// total. Le discriminant que le dossier croyait inexistant n'est pas dans la MATRICE (fermé le
/// 27/07 : vue-projection structurellement parfaite, rien ne l'identifie) -- il est dans la
/// PASSE. Et il y a de quoi choisir : 125 passes qualifiantes par image en moyenne, dont ~87
/// sur la couleur HDR.
///
/// LE CRITERE EST GENERIQUE -- forme de pipeline, rien d'autre : cible couleur attachee, NON
/// CARREE (une cible carree est un atlas d'ombres), format flottant HDR. C'est mot pour mot
/// celui que utilise deja pour epingler la couleur de scene.
/// Aucune adresse, aucun hash, aucune resolution, aucun nom de jeu.
///
/// ⛔ CE QUE CE FICHIER NE PROMET PAS. Attendu : 4,9 % d'intruses -> 1,3 %, soit environ 73 %
/// de moins. PAS zero : la passe de scene elle-meme en porte 3 sur 230. C'est une attenuation,
/// obtenue a la source au lieu d'un filtre pose apres coup -- ce n'est pas une execution.
///
/// ⚠️ LE RISQUE EST LA PUBLICATION, PAS L'INTRUSE, et c'est la borne INFERIEURE qui protege
/// (lecon du 29/07 : pour un composant dont le role est de refuser, prouver "il ne refuse
/// jamais plus" est la moitie inutile de la question). Une camera manquee fait ecrire ZERO sur
/// toute l'image. Donc la restriction s'auto-desarme, en deux etages :
/// 1. RATTRAPAGE -- deux images d'affilee avec des passes qualifiantes mais AUCUNE capture,
/// et la restriction se leve pour 300 images (comportement d'avant, a l'identique). Perte
/// bornee : 2 images sur 300, soit 0,7 %.
/// 2. DESARMEMENT -- cinq rattrapages, et la restriction se coupe pour la session, avec une
/// ligne de journal explicite. Si la passe HDR n'est pas fiable sur ce jeu, on le DIT au
/// lieu de saigner 2 images sur 3.
/// Le taux de publication se lit dans l'instrument qui existe deja ("MVPP capture window:
/// enq/pub") : mesure de reference du 29/07 au soir = 6 761 / 8 127 = 83,2 %. En dessous, le
/// correctif est mauvais quel que soit son gain sur les intruses.
///
/// Les compteurs sont approximatifs : OnDraw tourne sur le fil GPU, OnFrame sur celui de la
/// presentation. On ne batit aucune conclusion fine dessus -- seulement des ordres de grandeur.
///
static class MvppScenePass
{
public static readonly bool Enabled =
Environment.GetEnvironmentVariable("RYUJINX_MVPP_SCENEPASS") == "1";
private const int MissesBeforeCatchUp = 2;
private const int CatchUpFrames = 300;
private const int CatchUpsBeforeDisarm = 5;
private const int ReportMs = 5000;
private static bool _disarmed;
private static int _missStreak;
private static int _catchUpLeft;
private static int _catchUps;
private static bool _qualThisFrame;
private static int _frames;
private static int _captured;
private static int _skips;
private static int _catchUpFramesSeen;
private static long _lastReportMs;
///
/// Appelee sur un dessin qualifiant tant que l'image n'a pas encore sa camera. Rend false
/// pour SAUTER la tentative de capture sur ce dessin -- ce qui laisse la capture se faire
/// plus loin dans la MEME image, sur la passe de la scene.
///
public static bool Allows(GpuChannel channel)
{
_qualThisFrame = true;
if (_disarmed || _catchUpLeft > 0)
{
return true;
}
if (IsSceneColorPass(channel))
{
return true;
}
_skips++;
return false;
}
///
/// Reconnait la passe de la scene a la FORME de sa cible couleur : attachee, non carree,
/// format flottant HDR. Meme critere que . Une cible 8 bits
/// (interface, composition, passe auxiliaire) et une passe sans couleur du tout echouent
/// ici -- ce sont exactement les deux contextes qui portaient 96 % des intruses.
///
internal static bool IsSceneColorPass(GpuChannel channel)
{
Image.Texture col0 = channel.TextureManager.RenderTargetColor0;
if (col0 == null || col0.Info.Width == col0.Info.Height)
{
return false;
}
GAL.Format f = col0.Info.FormatInfo.Format;
return f == GAL.Format.R11G11B10Float || f == GAL.Format.R16G16B16A16Float;
}
///
/// Une fois par image presentee, AVANT que le drapeau de capture ne soit re-arme. C'est ici
/// que vit le filet de securite : une image qui avait des passes qualifiantes et n'a rien
/// capture est une image potentiellement perdue, et on ne l'accepte pas deux fois de suite.
///
public static void OnFrame(bool captured)
{
if (!_qualThisFrame)
{
// Image sans passe 3D (menu, chargement) : elle n'a jamais eu de camera a prendre,
// la compter comme un manque ferait declencher le rattrapage pour rien.
return;
}
_qualThisFrame = false;
_frames++;
if (_catchUpLeft > 0)
{
_catchUpLeft--;
_catchUpFramesSeen++;
}
if (captured)
{
_captured++;
_missStreak = 0;
}
else if (!_disarmed && _catchUpLeft == 0)
{
_missStreak++;
if (_missStreak >= MissesBeforeCatchUp)
{
_missStreak = 0;
_catchUps++;
_catchUpLeft = CatchUpFrames;
if (_catchUps >= CatchUpsBeforeDisarm)
{
_disarmed = true;
Logger.Warning?.Print(LogClass.Gpu,
$"MVPP SCENEPASS DESARME : {_catchUps} rattrapages, la passe de scene HDR " +
"n'est pas assez fiable sur ce jeu pour porter la capture. Retour au " +
"comportement d'avant pour le reste de la session.");
}
else
{
Logger.Info?.Print(LogClass.Gpu,
$"MVPP SCENEPASS rattrapage #{_catchUps} : {MissesBeforeCatchUp} images " +
$"d'affilee sans capture, restriction levee pour {CatchUpFrames} images.");
}
}
}
long now = Environment.TickCount64;
if (now - _lastReportMs >= ReportMs)
{
_lastReportMs = now;
Logger.Info?.Print(LogClass.Gpu,
$"MVPP SCENEPASS : {_frames} images 3D, {_captured} avec camera " +
$"({(_frames > 0 ? 100f * _captured / _frames : 0f):0.#} %), " +
$"{_skips} dessins sautes, {_catchUps} rattrapages " +
$"({_catchUpFramesSeen} images en rattrapage)" +
$"{(_disarmed ? " · DESARME" : "")}");
}
}
}
}