diff --git a/Data/Sys/GameSettings/DLS.ini b/Data/Sys/GameSettings/DLS.ini index a09d5bb36e..6bc49ef098 100644 --- a/Data/Sys/GameSettings/DLS.ini +++ b/Data/Sys/GameSettings/DLS.ini @@ -21,8 +21,7 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBToTextureEnable = False +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E5Z.ini b/Data/Sys/GameSettings/E5Z.ini index 1ddc86b65e..64955cf58d 100644 --- a/Data/Sys/GameSettings/E5Z.ini +++ b/Data/Sys/GameSettings/E5Z.ini @@ -19,5 +19,6 @@ EmulationStateId = 4 [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E62.ini b/Data/Sys/GameSettings/E62.ini index 29b4a6367c..61d1196d31 100644 --- a/Data/Sys/GameSettings/E62.ini +++ b/Data/Sys/GameSettings/E62.ini @@ -19,5 +19,6 @@ EmulationStateId = 4 [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E63.ini b/Data/Sys/GameSettings/E63.ini index 35c80facef..1ceb75d4fe 100644 --- a/Data/Sys/GameSettings/E63.ini +++ b/Data/Sys/GameSettings/E63.ini @@ -19,5 +19,6 @@ EmulationStateId = 4 [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E6V.ini b/Data/Sys/GameSettings/E6V.ini index 463925de6f..dc86ffff18 100644 --- a/Data/Sys/GameSettings/E6V.ini +++ b/Data/Sys/GameSettings/E6V.ini @@ -19,5 +19,6 @@ EmulationStateId = 4 [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E6W.ini b/Data/Sys/GameSettings/E6W.ini index 686673c761..6a12607d84 100644 --- a/Data/Sys/GameSettings/E6W.ini +++ b/Data/Sys/GameSettings/E6W.ini @@ -19,5 +19,6 @@ EmulationStateId = 4 [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E6X.ini b/Data/Sys/GameSettings/E6X.ini index 489f7f9fe0..09341815d7 100644 --- a/Data/Sys/GameSettings/E6X.ini +++ b/Data/Sys/GameSettings/E6X.ini @@ -19,5 +19,6 @@ EmulationStateId = 4 [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/G2V.ini b/Data/Sys/GameSettings/G2V.ini index 50c1ea4f81..7588a8dc0e 100644 --- a/Data/Sys/GameSettings/G2V.ini +++ b/Data/Sys/GameSettings/G2V.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs xfb real for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs xfb real for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/G4C.ini b/Data/Sys/GameSettings/G4C.ini index 586343f201..fd164730ef 100644 --- a/Data/Sys/GameSettings/G4C.ini +++ b/Data/Sys/GameSettings/G4C.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/G5N.ini b/Data/Sys/GameSettings/G5N.ini index e2568001ed..b6dd7db4df 100644 --- a/Data/Sys/GameSettings/G5N.ini +++ b/Data/Sys/GameSettings/G5N.ini @@ -19,5 +19,6 @@ EmulationIssues = [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/G6Q.ini b/Data/Sys/GameSettings/G6Q.ini index eea3b597c5..209851ce54 100644 --- a/Data/Sys/GameSettings/G6Q.ini +++ b/Data/Sys/GameSettings/G6Q.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -19,5 +19,6 @@ EmulationIssues = Needs real xfb for the videos to display. [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/G8M.ini b/Data/Sys/GameSettings/G8M.ini index fdec5667ec..32779226bc 100644 --- a/Data/Sys/GameSettings/G8M.ini +++ b/Data/Sys/GameSettings/G8M.ini @@ -20,6 +20,7 @@ EmulationIssues = Needs Efb to Ram for BBox (proper graphics). [Video_Hacks] EFBToTextureEnable = False BBoxEnable = True +ImmediateXFBEnable = False [Video_Stereoscopy] StereoConvergence = 545 diff --git a/Data/Sys/GameSettings/GAL.ini b/Data/Sys/GameSettings/GAL.ini index 5937932868..98c71287c8 100644 --- a/Data/Sys/GameSettings/GAL.ini +++ b/Data/Sys/GameSettings/GAL.ini @@ -19,3 +19,6 @@ EmulationIssues = [Video_Stereoscopy] StereoConvergence = 64 + +[Video_Hacks] +ImmediateXFBEnable = True diff --git a/Data/Sys/GameSettings/GAP.ini b/Data/Sys/GameSettings/GAP.ini index 65b1084a22..d35b493fb1 100644 --- a/Data/Sys/GameSettings/GAP.ini +++ b/Data/Sys/GameSettings/GAP.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GAU.ini b/Data/Sys/GameSettings/GAU.ini index d509c75328..e3cd010311 100644 --- a/Data/Sys/GameSettings/GAU.ini +++ b/Data/Sys/GameSettings/GAU.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GAY.ini b/Data/Sys/GameSettings/GAY.ini index 4188b18c99..a2b9d3c413 100644 --- a/Data/Sys/GameSettings/GAY.ini +++ b/Data/Sys/GameSettings/GAY.ini @@ -19,5 +19,6 @@ EmulationIssues = [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GBH.ini b/Data/Sys/GameSettings/GBH.ini index 67565ec87b..2a0450c2aa 100644 --- a/Data/Sys/GameSettings/GBH.ini +++ b/Data/Sys/GameSettings/GBH.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs Real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GBL.ini b/Data/Sys/GameSettings/GBL.ini index d3f0c34701..4438dfc546 100644 --- a/Data/Sys/GameSettings/GBL.ini +++ b/Data/Sys/GameSettings/GBL.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GBM.ini b/Data/Sys/GameSettings/GBM.ini index 78a39d3282..a90d449dc1 100644 --- a/Data/Sys/GameSettings/GBM.ini +++ b/Data/Sys/GameSettings/GBM.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GBV.ini b/Data/Sys/GameSettings/GBV.ini index 0b99af1684..4d18173c3a 100644 --- a/Data/Sys/GameSettings/GBV.ini +++ b/Data/Sys/GameSettings/GBV.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Needs Real xfb for videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs Real xfb for videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False \ No newline at end of file diff --git a/Data/Sys/GameSettings/GBW.ini b/Data/Sys/GameSettings/GBW.ini index 8c0a6a2b42..9c64d9baa2 100644 --- a/Data/Sys/GameSettings/GBW.ini +++ b/Data/Sys/GameSettings/GBW.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GC2.ini b/Data/Sys/GameSettings/GC2.ini index f2aee2ee90..dc240690a2 100644 --- a/Data/Sys/GameSettings/GC2.ini +++ b/Data/Sys/GameSettings/GC2.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real Xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real Xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GCE.ini b/Data/Sys/GameSettings/GCE.ini index 0be75c5dbe..2e97b23de4 100644 --- a/Data/Sys/GameSettings/GCE.ini +++ b/Data/Sys/GameSettings/GCE.ini @@ -2,9 +2,9 @@ [Core] [EmuState] EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GCN.ini b/Data/Sys/GameSettings/GCN.ini index e9674c67d6..7fbb0299dc 100644 --- a/Data/Sys/GameSettings/GCN.ini +++ b/Data/Sys/GameSettings/GCN.ini @@ -17,6 +17,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GCP.ini b/Data/Sys/GameSettings/GCP.ini index 4564e9e8e4..8bdfec5167 100644 --- a/Data/Sys/GameSettings/GCP.ini +++ b/Data/Sys/GameSettings/GCP.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to appear. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,8 +18,6 @@ EmulationIssues = Needs real xfb for videos to appear. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True [Video_Hacks] - +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GDD.ini b/Data/Sys/GameSettings/GDD.ini index b14da616cc..0ec8444a80 100644 --- a/Data/Sys/GameSettings/GDD.ini +++ b/Data/Sys/GameSettings/GDD.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GDG.ini b/Data/Sys/GameSettings/GDG.ini index 67abb45b12..b653bac936 100644 --- a/Data/Sys/GameSettings/GDG.ini +++ b/Data/Sys/GameSettings/GDG.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs Real Xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GDS.ini b/Data/Sys/GameSettings/GDS.ini index 019439a672..a07cf2b8df 100644 --- a/Data/Sys/GameSettings/GDS.ini +++ b/Data/Sys/GameSettings/GDS.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GDT.ini b/Data/Sys/GameSettings/GDT.ini index 53139ac043..8b75c322d7 100644 --- a/Data/Sys/GameSettings/GDT.ini +++ b/Data/Sys/GameSettings/GDT.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GE3.ini b/Data/Sys/GameSettings/GE3.ini index 90445bdd7c..a3a6e02263 100644 --- a/Data/Sys/GameSettings/GE3.ini +++ b/Data/Sys/GameSettings/GE3.ini @@ -19,5 +19,6 @@ EmulationIssues = [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GEO.ini b/Data/Sys/GameSettings/GEO.ini index d5500775e1..000bd30fa1 100644 --- a/Data/Sys/GameSettings/GEO.ini +++ b/Data/Sys/GameSettings/GEO.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 512 + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GF4.ini b/Data/Sys/GameSettings/GF4.ini index be08f7ce94..3cbbea2c38 100644 --- a/Data/Sys/GameSettings/GF4.ini +++ b/Data/Sys/GameSettings/GF4.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GFD.ini b/Data/Sys/GameSettings/GFD.ini index c3c6e3c8f3..60b32a18e7 100644 --- a/Data/Sys/GameSettings/GFD.ini +++ b/Data/Sys/GameSettings/GFD.ini @@ -18,6 +18,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GFF.ini b/Data/Sys/GameSettings/GFF.ini index a1e615e488..ae9fffcbfc 100644 --- a/Data/Sys/GameSettings/GFF.ini +++ b/Data/Sys/GameSettings/GFF.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GFG.ini b/Data/Sys/GameSettings/GFG.ini index 7e3d551cb4..71b48a9d88 100644 --- a/Data/Sys/GameSettings/GFG.ini +++ b/Data/Sys/GameSettings/GFG.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGE.ini b/Data/Sys/GameSettings/GGE.ini index 89757688e3..e62c7e68a8 100644 --- a/Data/Sys/GameSettings/GGE.ini +++ b/Data/Sys/GameSettings/GGE.ini @@ -18,9 +18,8 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] -EFBAccessEnable = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGN.ini b/Data/Sys/GameSettings/GGN.ini index 7dd5e59180..4b0dee79ba 100644 --- a/Data/Sys/GameSettings/GGN.ini +++ b/Data/Sys/GameSettings/GGN.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGR.ini b/Data/Sys/GameSettings/GGR.ini index d49f71d43c..adaa6b4337 100644 --- a/Data/Sys/GameSettings/GGR.ini +++ b/Data/Sys/GameSettings/GGR.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Needs Real Xfb to show videos. Graphic glitches. +EmulationIssues = Graphic glitches. [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs Real Xfb to show videos. Graphic glitches. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGS.ini b/Data/Sys/GameSettings/GGS.ini index b663c7b560..ddf5956832 100644 --- a/Data/Sys/GameSettings/GGS.ini +++ b/Data/Sys/GameSettings/GGS.ini @@ -20,3 +20,5 @@ EmulationIssues = [Video_Settings] SafeTextureCacheColorSamples = 512 +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGV.ini b/Data/Sys/GameSettings/GGV.ini index 3b518fd6b2..bfe9386122 100644 --- a/Data/Sys/GameSettings/GGV.ini +++ b/Data/Sys/GameSettings/GGV.ini @@ -2,10 +2,10 @@ [Core] [EmuState] EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnFrame] [ActionReplay] [Gecko] [Video_Settings] -UseXFB = True -UseRealXFB = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGY.ini b/Data/Sys/GameSettings/GGY.ini index d93df192a0..b84a2d72c1 100644 --- a/Data/Sys/GameSettings/GGY.ini +++ b/Data/Sys/GameSettings/GGY.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Needs Real XFB for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,8 +18,8 @@ EmulationIssues = Needs Real XFB for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True - SafeTextureCacheColorSamples = 512 +[Video_Hacks] +ImmediateXFBEnable = False + diff --git a/Data/Sys/GameSettings/GH2.ini b/Data/Sys/GameSettings/GH2.ini index 401a60f466..8f4a2c07c2 100644 --- a/Data/Sys/GameSettings/GH2.ini +++ b/Data/Sys/GameSettings/GH2.ini @@ -18,6 +18,7 @@ EmulationIssues = The game is slow. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GHN.ini b/Data/Sys/GameSettings/GHN.ini index 3ea3566e47..ea53e8fd32 100644 --- a/Data/Sys/GameSettings/GHN.ini +++ b/Data/Sys/GameSettings/GHN.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GHQ.ini b/Data/Sys/GameSettings/GHQ.ini index 2dab6952d0..57862fa744 100644 --- a/Data/Sys/GameSettings/GHQ.ini +++ b/Data/Sys/GameSettings/GHQ.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GHS.ini b/Data/Sys/GameSettings/GHS.ini index 0b528777a4..36b8a6bb05 100644 --- a/Data/Sys/GameSettings/GHS.ini +++ b/Data/Sys/GameSettings/GHS.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs Real Xfb for videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GHY.ini b/Data/Sys/GameSettings/GHY.ini index e600336082..334e0e1aff 100644 --- a/Data/Sys/GameSettings/GHY.ini +++ b/Data/Sys/GameSettings/GHY.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Needs Real Xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,6 @@ EmulationIssues = Needs Real Xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GIQ.ini b/Data/Sys/GameSettings/GIQ.ini index abf68cfd75..e90c36e580 100644 --- a/Data/Sys/GameSettings/GIQ.ini +++ b/Data/Sys/GameSettings/GIQ.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real XFB for videos to show up. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,6 +18,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GIZ.ini b/Data/Sys/GameSettings/GIZ.ini index 33b2329807..da39ea083c 100644 --- a/Data/Sys/GameSettings/GIZ.ini +++ b/Data/Sys/GameSettings/GIZ.ini @@ -20,5 +20,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GJB.ini b/Data/Sys/GameSettings/GJB.ini index c51995a177..3af361a955 100644 --- a/Data/Sys/GameSettings/GJB.ini +++ b/Data/Sys/GameSettings/GJB.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 5 -EmulationIssues = Videos need Real XFB to show up. Graphic glitches / unstable during videos. +EmulationIssues = Graphic glitches / unstable during videos. [OnLoad] # Add memory patches to be loaded once on boot here. @@ -19,6 +19,7 @@ EmulationIssues = Videos need Real XFB to show up. Graphic glitches / unstable d [Video_Settings] SafeTextureCacheColorSamples = 512 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GJN.ini b/Data/Sys/GameSettings/GJN.ini index 122aed90ea..9ec0d2572b 100644 --- a/Data/Sys/GameSettings/GJN.ini +++ b/Data/Sys/GameSettings/GJN.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GK4.ini b/Data/Sys/GameSettings/GK4.ini index db8893c112..c00292742e 100644 --- a/Data/Sys/GameSettings/GK4.ini +++ b/Data/Sys/GameSettings/GK4.ini @@ -18,9 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBToTextureEnable = False - +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GKB.ini b/Data/Sys/GameSettings/GKB.ini index d001e896bc..f3741dc6b4 100644 --- a/Data/Sys/GameSettings/GKB.ini +++ b/Data/Sys/GameSettings/GKB.ini @@ -19,9 +19,8 @@ EmulationIssues = # Add action replay cheats here. [Video_Hacks] +ImmediateXFBEnable = False EFBAccessEnable = False EFBToTextureEnable = False [Video_Settings] -UseXFB = True -UseRealXFB = False diff --git a/Data/Sys/GameSettings/GKH.ini b/Data/Sys/GameSettings/GKH.ini index 2b6b9db60d..569903f419 100644 --- a/Data/Sys/GameSettings/GKH.ini +++ b/Data/Sys/GameSettings/GKH.ini @@ -20,5 +20,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GKS.ini b/Data/Sys/GameSettings/GKS.ini index 3a795191fb..804d80b8bf 100644 --- a/Data/Sys/GameSettings/GKS.ini +++ b/Data/Sys/GameSettings/GKS.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to work. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to work. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GKZ.ini b/Data/Sys/GameSettings/GKZ.ini index eb607d56a7..943b66eb26 100644 --- a/Data/Sys/GameSettings/GKZ.ini +++ b/Data/Sys/GameSettings/GKZ.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real xfb for the videos to work. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GLG.ini b/Data/Sys/GameSettings/GLG.ini index a59d0d1343..174dd7b34a 100644 --- a/Data/Sys/GameSettings/GLG.ini +++ b/Data/Sys/GameSettings/GLG.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to work. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to work. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GLR.ini b/Data/Sys/GameSettings/GLR.ini index 45cfeeb4bb..7be194dc62 100644 --- a/Data/Sys/GameSettings/GLR.ini +++ b/Data/Sys/GameSettings/GLR.ini @@ -21,8 +21,7 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBToTextureEnable = False +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GLS.ini b/Data/Sys/GameSettings/GLS.ini index 5c20c7ede5..3ae3ec6259 100644 --- a/Data/Sys/GameSettings/GLS.ini +++ b/Data/Sys/GameSettings/GLS.ini @@ -7,7 +7,7 @@ SyncGPU = 1 [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -19,6 +19,6 @@ EmulationIssues = Needs Real Xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GM3.ini b/Data/Sys/GameSettings/GM3.ini index 5575cdf448..fff6ce4402 100644 --- a/Data/Sys/GameSettings/GM3.ini +++ b/Data/Sys/GameSettings/GM3.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GMD.ini b/Data/Sys/GameSettings/GMD.ini index babc65013f..851b80fb80 100644 --- a/Data/Sys/GameSettings/GMD.ini +++ b/Data/Sys/GameSettings/GMD.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GMH.ini b/Data/Sys/GameSettings/GMH.ini index 5636422e69..1f2cee41dd 100644 --- a/Data/Sys/GameSettings/GMH.ini +++ b/Data/Sys/GameSettings/GMH.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real Xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real Xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GMI.ini b/Data/Sys/GameSettings/GMI.ini index 544def3258..ca0a14994a 100644 --- a/Data/Sys/GameSettings/GMI.ini +++ b/Data/Sys/GameSettings/GMI.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GMN.ini b/Data/Sys/GameSettings/GMN.ini index 847e98d75b..85463db2cd 100644 --- a/Data/Sys/GameSettings/GMN.ini +++ b/Data/Sys/GameSettings/GMN.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Videos require real XFB. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Videos require real XFB. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GMX.ini b/Data/Sys/GameSettings/GMX.ini index 2c5fcc2acc..0c5f5f6621 100644 --- a/Data/Sys/GameSettings/GMX.ini +++ b/Data/Sys/GameSettings/GMX.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -21,5 +21,6 @@ EmulationIssues = Needs real xfb for the videos to display. EFBToTextureEnable = False [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GN4.ini b/Data/Sys/GameSettings/GN4.ini index 581de39978..c71cf370ba 100644 --- a/Data/Sys/GameSettings/GN4.ini +++ b/Data/Sys/GameSettings/GN4.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GN7.ini b/Data/Sys/GameSettings/GN7.ini index 77b593397b..f380040c97 100644 --- a/Data/Sys/GameSettings/GN7.ini +++ b/Data/Sys/GameSettings/GN7.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GNC.ini b/Data/Sys/GameSettings/GNC.ini index d45006d38c..ab094e97fd 100644 --- a/Data/Sys/GameSettings/GNC.ini +++ b/Data/Sys/GameSettings/GNC.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GNE.ini b/Data/Sys/GameSettings/GNE.ini index b52b2a132a..b9565ca919 100644 --- a/Data/Sys/GameSettings/GNE.ini +++ b/Data/Sys/GameSettings/GNE.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GNJ.ini b/Data/Sys/GameSettings/GNJ.ini index ab86f8dd64..c5e42f0c52 100644 --- a/Data/Sys/GameSettings/GNJ.ini +++ b/Data/Sys/GameSettings/GNJ.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs Real Xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GNN.ini b/Data/Sys/GameSettings/GNN.ini index af5742f5b2..aa5e02b19d 100644 --- a/Data/Sys/GameSettings/GNN.ini +++ b/Data/Sys/GameSettings/GNN.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -19,5 +19,6 @@ EmulationIssues = Needs real xfb for the videos to display. [Video_Settings] SafeTextureCacheColorSamples = 512 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GNWE69.ini b/Data/Sys/GameSettings/GNWE69.ini index 70fd9328ef..bc6a90a416 100644 --- a/Data/Sys/GameSettings/GNWE69.ini +++ b/Data/Sys/GameSettings/GNWE69.ini @@ -9,6 +9,9 @@ Patch Region = 0x7e000000 [OnFrame] # Add memory patches to be applied every frame here. +[Video_Hacks] +ImmediateXFBEnable = False + [ActionReplay] # Add action replay cheats here. $Max/Infinite Cash diff --git a/Data/Sys/GameSettings/GO2.ini b/Data/Sys/GameSettings/GO2.ini index 5ee098ab53..d052a4f48e 100644 --- a/Data/Sys/GameSettings/GO2.ini +++ b/Data/Sys/GameSettings/GO2.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -20,5 +20,6 @@ EmulationIssues = Needs Real Xfb for the videos to display. [Video] [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GP2.ini b/Data/Sys/GameSettings/GP2.ini index 7bf6171a40..3475a9b04e 100644 --- a/Data/Sys/GameSettings/GP2.ini +++ b/Data/Sys/GameSettings/GP2.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for the videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GP5.ini b/Data/Sys/GameSettings/GP5.ini index 760be43119..1ac01528b6 100644 --- a/Data/Sys/GameSettings/GP5.ini +++ b/Data/Sys/GameSettings/GP5.ini @@ -20,3 +20,5 @@ EmulationIssues = [Video_Hacks] EFBToTextureEnable = False +[Video_Hacks] +ImmediateXFBEnable = True diff --git a/Data/Sys/GameSettings/GPE.ini b/Data/Sys/GameSettings/GPE.ini index 165f1440c2..db9b095b9a 100644 --- a/Data/Sys/GameSettings/GPE.ini +++ b/Data/Sys/GameSettings/GPE.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = requires real XFB to avoid flickering +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = requires real XFB to avoid flickering # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GPK.ini b/Data/Sys/GameSettings/GPK.ini index dade44324b..1950e7c7b9 100644 --- a/Data/Sys/GameSettings/GPK.ini +++ b/Data/Sys/GameSettings/GPK.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs Real Xfb for videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GPS.ini b/Data/Sys/GameSettings/GPS.ini index 9ac18749d2..12d15ea70b 100644 --- a/Data/Sys/GameSettings/GPS.ini +++ b/Data/Sys/GameSettings/GPS.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for the videos to display. D3D11 has issues. +EmulationIssues = D3D11 has issues. [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,7 +18,8 @@ EmulationIssues = Needs Real Xfb for the videos to display. D3D11 has issues. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True SafeTextureCacheColorSamples = 512 +[Video_Hacks] +ImmediateXFBEnable = False + diff --git a/Data/Sys/GameSettings/GPT.ini b/Data/Sys/GameSettings/GPT.ini index 7c5c0593be..41cac59526 100644 --- a/Data/Sys/GameSettings/GPT.ini +++ b/Data/Sys/GameSettings/GPT.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,6 @@ EmulationIssues = Needs Real Xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GQX.ini b/Data/Sys/GameSettings/GQX.ini index 881b29b8e2..f8c6bf748e 100644 --- a/Data/Sys/GameSettings/GQX.ini +++ b/Data/Sys/GameSettings/GQX.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GRB.ini b/Data/Sys/GameSettings/GRB.ini index 4f13032ea7..e8444e076b 100644 --- a/Data/Sys/GameSettings/GRB.ini +++ b/Data/Sys/GameSettings/GRB.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GRH.ini b/Data/Sys/GameSettings/GRH.ini index 235f5209b9..21b104dec0 100644 --- a/Data/Sys/GameSettings/GRH.ini +++ b/Data/Sys/GameSettings/GRH.ini @@ -17,6 +17,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GRK.ini b/Data/Sys/GameSettings/GRK.ini index caa550db50..7b8309d3c1 100644 --- a/Data/Sys/GameSettings/GRK.ini +++ b/Data/Sys/GameSettings/GRK.ini @@ -18,7 +18,8 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 512 +[Video_Hacks] +ImmediateXFBEnable = False + diff --git a/Data/Sys/GameSettings/GRQ.ini b/Data/Sys/GameSettings/GRQ.ini index 2840f97730..f566192dfc 100644 --- a/Data/Sys/GameSettings/GRQ.ini +++ b/Data/Sys/GameSettings/GRQ.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Needs real XFB for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real XFB for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GRS.ini b/Data/Sys/GameSettings/GRS.ini index 26b57ec99b..f602657e36 100644 --- a/Data/Sys/GameSettings/GRS.ini +++ b/Data/Sys/GameSettings/GRS.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 512 + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GRU.ini b/Data/Sys/GameSettings/GRU.ini index d4a9879f38..2272281d2a 100644 --- a/Data/Sys/GameSettings/GRU.ini +++ b/Data/Sys/GameSettings/GRU.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs Real XFB to display videos. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,6 +18,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GRY.ini b/Data/Sys/GameSettings/GRY.ini index c10979b866..728964fcee 100644 --- a/Data/Sys/GameSettings/GRY.ini +++ b/Data/Sys/GameSettings/GRY.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real Xfb for videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs Real Xfb for videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GS2.ini b/Data/Sys/GameSettings/GS2.ini index 9856c2c65b..8d1b2a6243 100644 --- a/Data/Sys/GameSettings/GS2.ini +++ b/Data/Sys/GameSettings/GS2.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GSM.ini b/Data/Sys/GameSettings/GSM.ini index 3b317e640b..d13c7c4da1 100644 --- a/Data/Sys/GameSettings/GSM.ini +++ b/Data/Sys/GameSettings/GSM.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -20,5 +20,6 @@ EmulationIssues = Needs real xfb for the videos to display. [Video] [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GSO.ini b/Data/Sys/GameSettings/GSO.ini index 972933f1a1..36b396e3dc 100644 --- a/Data/Sys/GameSettings/GSO.ini +++ b/Data/Sys/GameSettings/GSO.ini @@ -18,7 +18,8 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 512 +[Video_Hacks] +ImmediateXFBEnable = False + diff --git a/Data/Sys/GameSettings/GSQ.ini b/Data/Sys/GameSettings/GSQ.ini index 98225298ff..1d47c09289 100644 --- a/Data/Sys/GameSettings/GSQ.ini +++ b/Data/Sys/GameSettings/GSQ.ini @@ -2,10 +2,10 @@ [Core] [EmuState] EmulationStateId = 3 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnFrame] [ActionReplay] [Gecko] [Video_Settings] -UseXFB = True -UseRealXFB = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GSS.ini b/Data/Sys/GameSettings/GSS.ini index 0a37f24396..46683704d1 100644 --- a/Data/Sys/GameSettings/GSS.ini +++ b/Data/Sys/GameSettings/GSS.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = EmulationStateId = 5 [OnLoad] @@ -18,6 +18,7 @@ EmulationStateId = 5 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GST.ini b/Data/Sys/GameSettings/GST.ini index cf5d656d07..06ccfcb415 100644 --- a/Data/Sys/GameSettings/GST.ini +++ b/Data/Sys/GameSettings/GST.ini @@ -17,5 +17,6 @@ EmulationStateId = 3 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GSW.ini b/Data/Sys/GameSettings/GSW.ini index f6aa412284..51783f24eb 100644 --- a/Data/Sys/GameSettings/GSW.ini +++ b/Data/Sys/GameSettings/GSW.ini @@ -21,9 +21,8 @@ EmulationStateId = 4 [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBToTextureEnable = False EFBEmulateFormatChanges = True +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GT3.ini b/Data/Sys/GameSettings/GT3.ini index 87eb3bef3f..4d34cb2abb 100644 --- a/Data/Sys/GameSettings/GT3.ini +++ b/Data/Sys/GameSettings/GT3.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -20,5 +20,6 @@ EmulationIssues = Needs real xfb for the videos to display. [Video] [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GT6.ini b/Data/Sys/GameSettings/GT6.ini index 25e6998265..137f91035b 100644 --- a/Data/Sys/GameSettings/GT6.ini +++ b/Data/Sys/GameSettings/GT6.ini @@ -18,9 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBAccessEnable = False - +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GT7.ini b/Data/Sys/GameSettings/GT7.ini index c59e054649..c95b2154e4 100644 --- a/Data/Sys/GameSettings/GT7.ini +++ b/Data/Sys/GameSettings/GT7.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Videos need real XFB to show up and loading screens show garbage. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,8 +18,8 @@ EmulationIssues = Videos need real XFB to show up and loading screens show garba # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True - SafeTextureCacheColorSamples = 512 +[Video_Hacks] +ImmediateXFBEnable = False + diff --git a/Data/Sys/GameSettings/GTR.ini b/Data/Sys/GameSettings/GTR.ini index adf6912304..8e2f451cda 100644 --- a/Data/Sys/GameSettings/GTR.ini +++ b/Data/Sys/GameSettings/GTR.ini @@ -2,10 +2,10 @@ [Core] [EmuState] EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = True +[Video_Hacks] +ImmediateXFBEnable = False [Gecko] diff --git a/Data/Sys/GameSettings/GTW.ini b/Data/Sys/GameSettings/GTW.ini index 9b50731724..d41bfcdee7 100644 --- a/Data/Sys/GameSettings/GTW.ini +++ b/Data/Sys/GameSettings/GTW.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GTZ.ini b/Data/Sys/GameSettings/GTZ.ini index b9ad4a7285..e06be5b4df 100644 --- a/Data/Sys/GameSettings/GTZ.ini +++ b/Data/Sys/GameSettings/GTZ.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real Xfb for videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real Xfb for videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GUT.ini b/Data/Sys/GameSettings/GUT.ini index 97997137e6..4757137fdb 100644 --- a/Data/Sys/GameSettings/GUT.ini +++ b/Data/Sys/GameSettings/GUT.ini @@ -19,8 +19,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Hacks] +ImmediateXFBEnable = False BBoxEnable = True [Video_Settings] -UseXFB = True -UseRealXFB = True diff --git a/Data/Sys/GameSettings/GUZ.ini b/Data/Sys/GameSettings/GUZ.ini index b26be53e53..63e0b72a43 100644 --- a/Data/Sys/GameSettings/GUZ.ini +++ b/Data/Sys/GameSettings/GUZ.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real XFB for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real XFB for videos to show up. # Add action replay cheats here. [Video_Settings] -UseRealXFB = True -UseXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GVC.ini b/Data/Sys/GameSettings/GVC.ini index dfaf95f58e..54f7b18922 100644 --- a/Data/Sys/GameSettings/GVC.ini +++ b/Data/Sys/GameSettings/GVC.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GVJ.ini b/Data/Sys/GameSettings/GVJ.ini index e472411799..70f24855c8 100644 --- a/Data/Sys/GameSettings/GVJ.ini +++ b/Data/Sys/GameSettings/GVJ.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GVO.ini b/Data/Sys/GameSettings/GVO.ini index 4bc7b884b6..6bf8c7a997 100644 --- a/Data/Sys/GameSettings/GVO.ini +++ b/Data/Sys/GameSettings/GVO.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GW7.ini b/Data/Sys/GameSettings/GW7.ini index 321afaaa94..45497fbd27 100644 --- a/Data/Sys/GameSettings/GW7.ini +++ b/Data/Sys/GameSettings/GW7.ini @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the video cutscenes to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GWL.ini b/Data/Sys/GameSettings/GWL.ini index 37ed3483f9..0c82f15eb8 100644 --- a/Data/Sys/GameSettings/GWL.ini +++ b/Data/Sys/GameSettings/GWL.ini @@ -17,3 +17,6 @@ EmulationIssues = [ActionReplay] # Add action replay cheats here. + +[Video_Hacks] +ImmediateXFBEnable = False \ No newline at end of file diff --git a/Data/Sys/GameSettings/GWY.ini b/Data/Sys/GameSettings/GWY.ini index 435a09bb36..0e29875e6b 100644 --- a/Data/Sys/GameSettings/GWY.ini +++ b/Data/Sys/GameSettings/GWY.ini @@ -21,9 +21,8 @@ EmulationIssues = Videos require real XFB. [Video] [Video_Settings] -UseXFB = True -UseRealXFB = True SafeTextureCacheColorSamples = 512 [Video_Hacks] +ImmediateXFBEnable = False EFBToTextureEnable = False diff --git a/Data/Sys/GameSettings/GX3.ini b/Data/Sys/GameSettings/GX3.ini index cb945a6e63..d717bd981c 100644 --- a/Data/Sys/GameSettings/GX3.ini +++ b/Data/Sys/GameSettings/GX3.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 3 -EmulationIssues = Needs real xfb for the videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,6 @@ EmulationIssues = Needs real xfb for the videos to show up. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GXM.ini b/Data/Sys/GameSettings/GXM.ini index 5e92d676a2..0607f29d33 100644 --- a/Data/Sys/GameSettings/GXM.ini +++ b/Data/Sys/GameSettings/GXM.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GYT.ini b/Data/Sys/GameSettings/GYT.ini index 63e73f944e..97fa2b2dbc 100644 --- a/Data/Sys/GameSettings/GYT.ini +++ b/Data/Sys/GameSettings/GYT.ini @@ -23,5 +23,6 @@ EmulationIssues = EFBToTextureEnable = False [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GZP.ini b/Data/Sys/GameSettings/GZP.ini index e64360681e..4966225bbc 100644 --- a/Data/Sys/GameSettings/GZP.ini +++ b/Data/Sys/GameSettings/GZP.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/HAT.ini b/Data/Sys/GameSettings/HAT.ini index 4ff45b44fc..6ebeeac01b 100644 --- a/Data/Sys/GameSettings/HAT.ini +++ b/Data/Sys/GameSettings/HAT.ini @@ -20,5 +20,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/HCL.ini b/Data/Sys/GameSettings/HCL.ini index 5fd4966ef5..9706a074e6 100644 --- a/Data/Sys/GameSettings/HCL.ini +++ b/Data/Sys/GameSettings/HCL.ini @@ -21,5 +21,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/HCS.ini b/Data/Sys/GameSettings/HCS.ini index 556f55760a..de4990d5e2 100644 --- a/Data/Sys/GameSettings/HCS.ini +++ b/Data/Sys/GameSettings/HCS.ini @@ -20,5 +20,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/L.ini b/Data/Sys/GameSettings/L.ini index 5c9ae6ca7f..cae67b12b3 100644 --- a/Data/Sys/GameSettings/L.ini +++ b/Data/Sys/GameSettings/L.ini @@ -11,5 +11,6 @@ EmulationIssues = [Video_Settings] SuggestedAspectRatio = 2 SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MAK.ini b/Data/Sys/GameSettings/MAK.ini index 641a33f1fc..7a68d6d26f 100644 --- a/Data/Sys/GameSettings/MAK.ini +++ b/Data/Sys/GameSettings/MAK.ini @@ -6,5 +6,6 @@ EmulationIssues = Use Opengl, D3D has issues. EmulationStateId = 4 [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MB3.ini b/Data/Sys/GameSettings/MB3.ini index c2e607d744..7a078d2906 100644 --- a/Data/Sys/GameSettings/MB3.ini +++ b/Data/Sys/GameSettings/MB3.ini @@ -6,5 +6,6 @@ EmulationIssues = Use Opengl, D3D has issues. EmulationStateId = 4 [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MBA.ini b/Data/Sys/GameSettings/MBA.ini index 34186a48b2..d57bc43464 100644 --- a/Data/Sys/GameSettings/MBA.ini +++ b/Data/Sys/GameSettings/MBA.ini @@ -6,5 +6,6 @@ EmulationIssues = Use Opengl, D3D has issues. EmulationStateId = 4 [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCD.ini b/Data/Sys/GameSettings/MCD.ini index ee31fcd189..826a23ca84 100644 --- a/Data/Sys/GameSettings/MCD.ini +++ b/Data/Sys/GameSettings/MCD.ini @@ -6,5 +6,6 @@ EmulationIssues = Use Opengl, D3D has issues. EmulationStateId = 4 [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCS.ini b/Data/Sys/GameSettings/MCS.ini index 2c4b2380c9..85183c71f4 100644 --- a/Data/Sys/GameSettings/MCS.ini +++ b/Data/Sys/GameSettings/MCS.ini @@ -6,5 +6,6 @@ EmulationIssues = Use Opengl, D3D has issues. EmulationStateId = 4 [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCV.ini b/Data/Sys/GameSettings/MCV.ini index 754c185e35..3a9cab1aab 100644 --- a/Data/Sys/GameSettings/MCV.ini +++ b/Data/Sys/GameSettings/MCV.ini @@ -6,5 +6,6 @@ EmulationIssues = Use Opengl, D3D has issues. EmulationStateId = 4 [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCW.ini b/Data/Sys/GameSettings/MCW.ini index 233e3dd8fd..c761b9fb79 100644 --- a/Data/Sys/GameSettings/MCW.ini +++ b/Data/Sys/GameSettings/MCW.ini @@ -6,5 +6,6 @@ EmulationIssues = Use Opengl, D3D has issues. EmulationStateId = 4 [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCY.ini b/Data/Sys/GameSettings/MCY.ini index cec1d19cbc..2043159c32 100644 --- a/Data/Sys/GameSettings/MCY.ini +++ b/Data/Sys/GameSettings/MCY.ini @@ -6,5 +6,6 @@ EmulationIssues = Use Opengl, D3D has issues. EmulationStateId = 4 [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCZ.ini b/Data/Sys/GameSettings/MCZ.ini index 42496fb872..19017725f6 100644 --- a/Data/Sys/GameSettings/MCZ.ini +++ b/Data/Sys/GameSettings/MCZ.ini @@ -7,5 +7,6 @@ EmulationStateId = 4 [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/PZL.ini b/Data/Sys/GameSettings/PZL.ini index 4746515384..1b68d6e91d 100644 --- a/Data/Sys/GameSettings/PZL.ini +++ b/Data/Sys/GameSettings/PZL.ini @@ -21,6 +21,7 @@ EmulationIssues = Hold B while booting the game to enable Progressive Scan for N [Video_Hacks] EFBToTextureEnable = False +ImmediateXFBEnable = False [Video_Settings] SafeTextureCacheColorSamples = 0 diff --git a/Data/Sys/GameSettings/R2G.ini b/Data/Sys/GameSettings/R2G.ini index 651c756bcb..ccfff8bfb2 100644 --- a/Data/Sys/GameSettings/R2G.ini +++ b/Data/Sys/GameSettings/R2G.ini @@ -18,9 +18,8 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBEmulateFormatChanges = True +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/R3A.ini b/Data/Sys/GameSettings/R3A.ini index 49d71e72e7..d75891f3db 100644 --- a/Data/Sys/GameSettings/R3A.ini +++ b/Data/Sys/GameSettings/R3A.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Requires Real XFB and EFB2RAM to fix various issues. +EmulationIssues = Requires EFB2RAM to fix various issues. [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,8 +18,7 @@ EmulationIssues = Requires Real XFB and EFB2RAM to fix various issues. # Add action replay cheats here. [Video_Hacks] +ImmediateXFBEnable = False EFBToTextureEnable = False [Video_Settings] -UseXFB = True -UseRealXFB = True diff --git a/Data/Sys/GameSettings/R3B.ini b/Data/Sys/GameSettings/R3B.ini index 262f9f1d46..012cff5959 100644 --- a/Data/Sys/GameSettings/R3B.ini +++ b/Data/Sys/GameSettings/R3B.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/R3D.ini b/Data/Sys/GameSettings/R3D.ini index 190e8c5cca..02fbd2ae55 100644 --- a/Data/Sys/GameSettings/R3D.ini +++ b/Data/Sys/GameSettings/R3D.ini @@ -18,6 +18,7 @@ EmulationIssues = Automatic framelimit is problematic. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/R3M.ini b/Data/Sys/GameSettings/R3M.ini index 733da1c50d..fdaa7e24e2 100644 --- a/Data/Sys/GameSettings/R3M.ini +++ b/Data/Sys/GameSettings/R3M.ini @@ -19,4 +19,4 @@ EmulationIssues = Disable PAL60 (EuRGB60) to avoid a black bar appearing. [Video_Hacks] EFBToTextureEnable = False - +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/R4F.ini b/Data/Sys/GameSettings/R4F.ini index 0ee28c12b7..84d1bea7f4 100644 --- a/Data/Sys/GameSettings/R4F.ini +++ b/Data/Sys/GameSettings/R4F.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Requires Real XFB and EFB2RAM to fix various issues. +EmulationIssues = Requires EFB2RAM to fix various issues. [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,8 +18,8 @@ EmulationIssues = Requires Real XFB and EFB2RAM to fix various issues. # Add action replay cheats here. [Video_Hacks] +ImmediateXFBEnable = False EFBToTextureEnable = False [Video_Settings] -UseXFB = True -UseRealXFB = True + diff --git a/Data/Sys/GameSettings/R7G.ini b/Data/Sys/GameSettings/R7G.ini index 9d64cf36b1..04266c3bb8 100644 --- a/Data/Sys/GameSettings/R7G.ini +++ b/Data/Sys/GameSettings/R7G.ini @@ -19,6 +19,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/R8L.ini b/Data/Sys/GameSettings/R8L.ini index 04f958bf72..60520ccbaf 100644 --- a/Data/Sys/GameSettings/R8L.ini +++ b/Data/Sys/GameSettings/R8L.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs Real XFB in order to be playable. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs Real XFB in order to be playable. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RBO.ini b/Data/Sys/GameSettings/RBO.ini index 5fc9cd2dd6..e84e7dd048 100644 --- a/Data/Sys/GameSettings/RBO.ini +++ b/Data/Sys/GameSettings/RBO.ini @@ -18,9 +18,10 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Enhancements] MaxAnisotropy = 0 ForceFiltering = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RBR.ini b/Data/Sys/GameSettings/RBR.ini index 28bba3b1b4..22e5221dc7 100644 --- a/Data/Sys/GameSettings/RBR.ini +++ b/Data/Sys/GameSettings/RBR.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RBW.ini b/Data/Sys/GameSettings/RBW.ini index 208bd1031a..88524635d2 100644 --- a/Data/Sys/GameSettings/RBW.ini +++ b/Data/Sys/GameSettings/RBW.ini @@ -17,3 +17,6 @@ EmulationIssues = [ActionReplay] # Add action replay cheats here. + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RCL.ini b/Data/Sys/GameSettings/RCL.ini index 0f8ebfc096..cb0a176b7f 100644 --- a/Data/Sys/GameSettings/RCL.ini +++ b/Data/Sys/GameSettings/RCL.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for the video cutscenes to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the video cutscenes to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RED.ini b/Data/Sys/GameSettings/RED.ini index 155b1cc5f7..3955ebdc58 100644 --- a/Data/Sys/GameSettings/RED.ini +++ b/Data/Sys/GameSettings/RED.ini @@ -17,3 +17,5 @@ EmulationIssues = Nunchuk doesn't work (both real and emulated). [ActionReplay] # Add action replay cheats here. +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RF7.ini b/Data/Sys/GameSettings/RF7.ini index c71ae4faff..cc9569746b 100644 --- a/Data/Sys/GameSettings/RF7.ini +++ b/Data/Sys/GameSettings/RF7.ini @@ -17,3 +17,5 @@ EmulationIssues = [ActionReplay] # Add action replay cheats here. +[Video_Hacks] +ImmediateXFBEnable = True diff --git a/Data/Sys/GameSettings/RG6.ini b/Data/Sys/GameSettings/RG6.ini index 8cdb19157d..e068ac7053 100644 --- a/Data/Sys/GameSettings/RG6.ini +++ b/Data/Sys/GameSettings/RG6.ini @@ -18,9 +18,10 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Enhancements] MaxAnisotropy = 0 ForceFiltering = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RGW.ini b/Data/Sys/GameSettings/RGW.ini index 9ddb02d1e2..4164edd403 100644 --- a/Data/Sys/GameSettings/RGW.ini +++ b/Data/Sys/GameSettings/RGW.ini @@ -18,6 +18,7 @@ EmulationIssues = Efb to ram is needed for certain ingame functions but it will # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 512 + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RH8.ini b/Data/Sys/GameSettings/RH8.ini index 9aef363f80..18f882d28e 100644 --- a/Data/Sys/GameSettings/RH8.ini +++ b/Data/Sys/GameSettings/RH8.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real Xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Needs real Xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RIZ.ini b/Data/Sys/GameSettings/RIZ.ini index 24bceefeb3..e4de9fd44b 100644 --- a/Data/Sys/GameSettings/RIZ.ini +++ b/Data/Sys/GameSettings/RIZ.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RJ2.ini b/Data/Sys/GameSettings/RJ2.ini index 848b521f61..f47696ebb3 100644 --- a/Data/Sys/GameSettings/RJ2.ini +++ b/Data/Sys/GameSettings/RJ2.ini @@ -18,10 +18,11 @@ EmulationIssues = Needs STC to prevent glitches and it runs slow. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 0 [Video_Enhancements] MaxAnisotropy = 0 ForceFiltering = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RLJ.ini b/Data/Sys/GameSettings/RLJ.ini index 6fd2ce5617..d2cf2e23fd 100644 --- a/Data/Sys/GameSettings/RLJ.ini +++ b/Data/Sys/GameSettings/RLJ.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 5 -EmulationIssues = Needs real xfb for the videos to display. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Needs real xfb for the videos to display. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RLS.ini b/Data/Sys/GameSettings/RLS.ini index d66ffe4512..e82d86acce 100644 --- a/Data/Sys/GameSettings/RLS.ini +++ b/Data/Sys/GameSettings/RLS.ini @@ -23,5 +23,6 @@ EmulationIssues = EFBToTextureEnable = False [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RM9.ini b/Data/Sys/GameSettings/RM9.ini new file mode 100644 index 0000000000..ca72c7fbe2 --- /dev/null +++ b/Data/Sys/GameSettings/RM9.ini @@ -0,0 +1,23 @@ +# RM9PGM, RM9EGM - Mushroom Men: The Spore Wars + +[Core] +# Values set here will override the main Dolphin settings. + +[EmuState] +# The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = + +[OnLoad] +# Add memory patches to be loaded once on boot here. + +[OnFrame] +# Add memory patches to be applied every frame here. + +[ActionReplay] +# Add action replay cheats here. + +[Video_Settings] + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RMH.ini b/Data/Sys/GameSettings/RMH.ini index 2ab2870c99..e2fb0046a4 100644 --- a/Data/Sys/GameSettings/RMH.ini +++ b/Data/Sys/GameSettings/RMH.ini @@ -18,10 +18,8 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBAccessEnable = False EFBToTextureEnable = False - +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RMO.ini b/Data/Sys/GameSettings/RMO.ini index c9968455ed..df2150a2fd 100644 --- a/Data/Sys/GameSettings/RMO.ini +++ b/Data/Sys/GameSettings/RMO.ini @@ -18,5 +18,6 @@ EmulationIssues = Flickers if XFB is disabled # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RNO.ini b/Data/Sys/GameSettings/RNO.ini index e1f56b62af..64ea06a808 100644 --- a/Data/Sys/GameSettings/RNO.ini +++ b/Data/Sys/GameSettings/RNO.ini @@ -18,9 +18,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBToTextureEnable = False - +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RO3.ini b/Data/Sys/GameSettings/RO3.ini index 5081bfca2f..c03ef4e497 100644 --- a/Data/Sys/GameSettings/RO3.ini +++ b/Data/Sys/GameSettings/RO3.ini @@ -18,6 +18,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RO9.ini b/Data/Sys/GameSettings/RO9.ini index 8e32f7bfad..21e772708a 100644 --- a/Data/Sys/GameSettings/RO9.ini +++ b/Data/Sys/GameSettings/RO9.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RRZ.ini b/Data/Sys/GameSettings/RRZ.ini index 78d8f48d61..8cf6599aef 100644 --- a/Data/Sys/GameSettings/RRZ.ini +++ b/Data/Sys/GameSettings/RRZ.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RSB.ini b/Data/Sys/GameSettings/RSB.ini index 783cc4770b..f283352c23 100644 --- a/Data/Sys/GameSettings/RSB.ini +++ b/Data/Sys/GameSettings/RSB.ini @@ -19,3 +19,6 @@ EmulationIssues = Classic mode score report needs real xfb. Nes masterpieces and [Video_Stereoscopy] StereoConvergence = 136 + +[Video_Hacks] +ImmediateXFBEnable = True diff --git a/Data/Sys/GameSettings/RSX.ini b/Data/Sys/GameSettings/RSX.ini index b0b7eca79d..f1fd2c5075 100644 --- a/Data/Sys/GameSettings/RSX.ini +++ b/Data/Sys/GameSettings/RSX.ini @@ -18,9 +18,8 @@ EmulationIssues = Needs Wii nand dump (reconnect wiimote if necessary). EFB cpu # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] -EFBAccessEnable = True +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RT3.ini b/Data/Sys/GameSettings/RT3.ini index 16ebecc964..077b1e0213 100644 --- a/Data/Sys/GameSettings/RT3.ini +++ b/Data/Sys/GameSettings/RT3.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RTZ.ini b/Data/Sys/GameSettings/RTZ.ini index 7d5f9b9260..934b54d94a 100644 --- a/Data/Sys/GameSettings/RTZ.ini +++ b/Data/Sys/GameSettings/RTZ.ini @@ -18,6 +18,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RXX.ini b/Data/Sys/GameSettings/RXX.ini index e503062656..7ec5df885d 100644 --- a/Data/Sys/GameSettings/RXX.ini +++ b/Data/Sys/GameSettings/RXX.ini @@ -18,9 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBEmulateFormatChanges = True - +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RZO.ini b/Data/Sys/GameSettings/RZO.ini index a51e720995..8fc2994c7c 100644 --- a/Data/Sys/GameSettings/RZO.ini +++ b/Data/Sys/GameSettings/RZO.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 0 + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/S72.ini b/Data/Sys/GameSettings/S72.ini index c45eb5a443..bbe6b9a798 100644 --- a/Data/Sys/GameSettings/S72.ini +++ b/Data/Sys/GameSettings/S72.ini @@ -18,9 +18,8 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 0 [Video_Hacks] EFBToTextureEnable = False +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SBX.ini b/Data/Sys/GameSettings/SBX.ini index 2091f4b1a4..7ba6af51b2 100644 --- a/Data/Sys/GameSettings/SBX.ini +++ b/Data/Sys/GameSettings/SBX.ini @@ -20,5 +20,6 @@ EmulationIssues = Wiimote cursor misaligned [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SDM.ini b/Data/Sys/GameSettings/SDM.ini index 098d70b75d..19b1b1519a 100644 --- a/Data/Sys/GameSettings/SDM.ini +++ b/Data/Sys/GameSettings/SDM.ini @@ -18,8 +18,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBToTextureEnable = False +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SFI.ini b/Data/Sys/GameSettings/SFI.ini index 5b3fb8ad81..535f7ae0be 100644 --- a/Data/Sys/GameSettings/SFI.ini +++ b/Data/Sys/GameSettings/SFI.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Needs real xfb for videos to show up. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -19,6 +19,7 @@ EmulationIssues = Needs real xfb for videos to show up. [Video_Settings] SafeTextureCacheColorSamples = 512 -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SG8.ini b/Data/Sys/GameSettings/SG8.ini index da8ca9a2f3..fe0847d40d 100644 --- a/Data/Sys/GameSettings/SG8.ini +++ b/Data/Sys/GameSettings/SG8.ini @@ -18,8 +18,7 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBToTextureEnable = False +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SGV.ini b/Data/Sys/GameSettings/SGV.ini new file mode 100644 index 0000000000..ac1597be91 --- /dev/null +++ b/Data/Sys/GameSettings/SGV.ini @@ -0,0 +1,21 @@ +# SGVEAF, SGVPAF - Go Vacation + +[Core] +# Values set here will override the main Dolphin settings. + +[EmuState] +# The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = + +[OnLoad] +# Add memory patches to be loaded once on boot here. + +[OnFrame] +# Add memory patches to be applied every frame here. + +[ActionReplay] +# Add action replay cheats here. + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SHW.ini b/Data/Sys/GameSettings/SHW.ini index 8024cc335c..02585df754 100644 --- a/Data/Sys/GameSettings/SHW.ini +++ b/Data/Sys/GameSettings/SHW.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Requires Virtual XFB to prevent flickering. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,5 +18,6 @@ EmulationIssues = Requires Virtual XFB to prevent flickering. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SJE.ini b/Data/Sys/GameSettings/SJE.ini index d5fba19fc4..49e5f97412 100644 --- a/Data/Sys/GameSettings/SJE.ini +++ b/Data/Sys/GameSettings/SJE.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SKA.ini b/Data/Sys/GameSettings/SKA.ini index d5f2a80ecb..b719b2fb6d 100644 --- a/Data/Sys/GameSettings/SKA.ini +++ b/Data/Sys/GameSettings/SKA.ini @@ -18,5 +18,6 @@ EmulationIssues = Microphone input does not work because of missing IOS USB supp # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SKC.ini b/Data/Sys/GameSettings/SKC.ini index 56828ac2c6..7c61ba67f9 100644 --- a/Data/Sys/GameSettings/SKC.ini +++ b/Data/Sys/GameSettings/SKC.ini @@ -20,5 +20,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SKG.ini b/Data/Sys/GameSettings/SKG.ini index d30782c678..435f8c3d07 100644 --- a/Data/Sys/GameSettings/SKG.ini +++ b/Data/Sys/GameSettings/SKG.ini @@ -18,5 +18,6 @@ EmulationIssues = Microphone input does not work because of missing IOS USB supp # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SKJ.ini b/Data/Sys/GameSettings/SKJ.ini index 41c21063d8..50e415b3aa 100644 --- a/Data/Sys/GameSettings/SKJ.ini +++ b/Data/Sys/GameSettings/SKJ.ini @@ -18,8 +18,8 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False - SafeTextureCacheColorSamples = 0 +[Video_Hacks] +ImmediateXFBEnable = False + diff --git a/Data/Sys/GameSettings/SKO.ini b/Data/Sys/GameSettings/SKO.ini index 26ac3e3d51..5cbd46cfe4 100644 --- a/Data/Sys/GameSettings/SKO.ini +++ b/Data/Sys/GameSettings/SKO.ini @@ -18,5 +18,6 @@ EmulationIssues = Microphone input does not work because of missing IOS USB supp # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SKV.ini b/Data/Sys/GameSettings/SKV.ini index 6a72f34012..5b6f648ceb 100644 --- a/Data/Sys/GameSettings/SKV.ini +++ b/Data/Sys/GameSettings/SKV.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SLW.ini b/Data/Sys/GameSettings/SLW.ini index 9fca2bf24f..4165513f3a 100644 --- a/Data/Sys/GameSettings/SLW.ini +++ b/Data/Sys/GameSettings/SLW.ini @@ -18,6 +18,7 @@ EmulationIssues = Needs Real Xfb for the pointer to appear. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SMF.ini b/Data/Sys/GameSettings/SMF.ini index 427cbf5ba1..a607627467 100644 --- a/Data/Sys/GameSettings/SMF.ini +++ b/Data/Sys/GameSettings/SMF.ini @@ -19,7 +19,7 @@ EmulationIssues = [Video_Settings] SafeTextureCacheColorSamples = 0 -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SNY.ini b/Data/Sys/GameSettings/SNY.ini index 951ba5b9e0..4297a659b6 100644 --- a/Data/Sys/GameSettings/SNY.ini +++ b/Data/Sys/GameSettings/SNY.ini @@ -13,5 +13,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SOS.ini b/Data/Sys/GameSettings/SOS.ini index e960e3bd14..558bfd3ada 100644 --- a/Data/Sys/GameSettings/SOS.ini +++ b/Data/Sys/GameSettings/SOS.ini @@ -20,5 +20,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SPR.ini b/Data/Sys/GameSettings/SPR.ini index d5fa04c374..124e7dee8f 100644 --- a/Data/Sys/GameSettings/SPR.ini +++ b/Data/Sys/GameSettings/SPR.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SSR.ini b/Data/Sys/GameSettings/SSR.ini index 4cb29e0444..e66ac7198d 100644 --- a/Data/Sys/GameSettings/SSR.ini +++ b/Data/Sys/GameSettings/SSR.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SST.ini b/Data/Sys/GameSettings/SST.ini index b151d4df37..24b1b66ef5 100644 --- a/Data/Sys/GameSettings/SST.ini +++ b/Data/Sys/GameSettings/SST.ini @@ -20,5 +20,6 @@ EmulationIssues = [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SSZ.ini b/Data/Sys/GameSettings/SSZ.ini index 690ead5547..2c34e4fb48 100644 --- a/Data/Sys/GameSettings/SSZ.ini +++ b/Data/Sys/GameSettings/SSZ.ini @@ -18,6 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/STK.ini b/Data/Sys/GameSettings/STK.ini index 5700ecde68..0327877dfa 100644 --- a/Data/Sys/GameSettings/STK.ini +++ b/Data/Sys/GameSettings/STK.ini @@ -17,3 +17,5 @@ EmulationStateId = 5 [ActionReplay] # Add action replay cheats here. +[Video_Hacks] +ImmediateXFBEnable = True diff --git a/Data/Sys/GameSettings/SU7.ini b/Data/Sys/GameSettings/SU7.ini index 83cc84cb5d..68d6e811c8 100644 --- a/Data/Sys/GameSettings/SU7.ini +++ b/Data/Sys/GameSettings/SU7.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SUK.ini b/Data/Sys/GameSettings/SUK.ini index c758320af7..097daa441b 100644 --- a/Data/Sys/GameSettings/SUK.ini +++ b/Data/Sys/GameSettings/SUK.ini @@ -18,6 +18,7 @@ EmulationIssues = Some minigames need XFB to work. # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SVV.ini b/Data/Sys/GameSettings/SVV.ini index 195c67747c..cf1a64aa90 100644 --- a/Data/Sys/GameSettings/SVV.ini +++ b/Data/Sys/GameSettings/SVV.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SVZ.ini b/Data/Sys/GameSettings/SVZ.ini index 542009dde9..011a7f5490 100644 --- a/Data/Sys/GameSettings/SVZ.ini +++ b/Data/Sys/GameSettings/SVZ.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SX7.ini b/Data/Sys/GameSettings/SX7.ini index 1dea6c236a..daa2f5d104 100644 --- a/Data/Sys/GameSettings/SX7.ini +++ b/Data/Sys/GameSettings/SX7.ini @@ -20,6 +20,7 @@ EmulationIssues = Sound issues. [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 0 + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/W3M.ini b/Data/Sys/GameSettings/W3M.ini index 6c38776402..ac24006660 100644 --- a/Data/Sys/GameSettings/W3M.ini +++ b/Data/Sys/GameSettings/W3M.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WA2.ini b/Data/Sys/GameSettings/WA2.ini index 1576c436db..01fecf1fff 100644 --- a/Data/Sys/GameSettings/WA2.ini +++ b/Data/Sys/GameSettings/WA2.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB2.ini b/Data/Sys/GameSettings/WB2.ini index 73d42c7487..e571663414 100644 --- a/Data/Sys/GameSettings/WB2.ini +++ b/Data/Sys/GameSettings/WB2.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB3.ini b/Data/Sys/GameSettings/WB3.ini index 3fb79cab3d..85c7191caa 100644 --- a/Data/Sys/GameSettings/WB3.ini +++ b/Data/Sys/GameSettings/WB3.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB6.ini b/Data/Sys/GameSettings/WB6.ini index 665409fb83..6a6d997713 100644 --- a/Data/Sys/GameSettings/WB6.ini +++ b/Data/Sys/GameSettings/WB6.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB7.ini b/Data/Sys/GameSettings/WB7.ini index c9cd6b3135..3a65d0e4a6 100644 --- a/Data/Sys/GameSettings/WB7.ini +++ b/Data/Sys/GameSettings/WB7.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB8.ini b/Data/Sys/GameSettings/WB8.ini index 5524348a3b..0461fcc431 100644 --- a/Data/Sys/GameSettings/WB8.ini +++ b/Data/Sys/GameSettings/WB8.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Requires Virtual XFB to prevent flickering. +EmulationIssues = [OnLoad] # Add memory patches to be loaded once on boot here. @@ -17,6 +17,5 @@ EmulationIssues = Requires Virtual XFB to prevent flickering. [ActionReplay] # Add action replay cheats here. -[Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WBX.ini b/Data/Sys/GameSettings/WBX.ini index 7b5fa11937..ac0e1c0499 100644 --- a/Data/Sys/GameSettings/WBX.ini +++ b/Data/Sys/GameSettings/WBX.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WBY.ini b/Data/Sys/GameSettings/WBY.ini index 449f891eae..f29978c9dd 100644 --- a/Data/Sys/GameSettings/WBY.ini +++ b/Data/Sys/GameSettings/WBY.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WBZ.ini b/Data/Sys/GameSettings/WBZ.ini index c13698f6bf..7659e6521a 100644 --- a/Data/Sys/GameSettings/WBZ.ini +++ b/Data/Sys/GameSettings/WBZ.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WC6.ini b/Data/Sys/GameSettings/WC6.ini index 0aa9af9c51..889e49dc17 100644 --- a/Data/Sys/GameSettings/WC6.ini +++ b/Data/Sys/GameSettings/WC6.ini @@ -16,5 +16,6 @@ EmulationIssues = Disable PAL60 (EuRGB60) mode [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WCH.ini b/Data/Sys/GameSettings/WCH.ini index 1578143540..bde934a27f 100644 --- a/Data/Sys/GameSettings/WCH.ini +++ b/Data/Sys/GameSettings/WCH.ini @@ -15,5 +15,6 @@ EFBEmulateFormatChanges = True EFBToTextureEnable = False [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WDO.ini b/Data/Sys/GameSettings/WDO.ini index 52b66c0987..8bebc9138f 100644 --- a/Data/Sys/GameSettings/WDO.ini +++ b/Data/Sys/GameSettings/WDO.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WFH.ini b/Data/Sys/GameSettings/WFH.ini index b4dc6da328..ad96eb5bb3 100644 --- a/Data/Sys/GameSettings/WFH.ini +++ b/Data/Sys/GameSettings/WFH.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WFU.ini b/Data/Sys/GameSettings/WFU.ini index 3251d39c83..d3af396a23 100644 --- a/Data/Sys/GameSettings/WFU.ini +++ b/Data/Sys/GameSettings/WFU.ini @@ -6,5 +6,5 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WGG.ini b/Data/Sys/GameSettings/WGG.ini index 4b41cbfa90..56d98ddda3 100644 --- a/Data/Sys/GameSettings/WGG.ini +++ b/Data/Sys/GameSettings/WGG.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WGL.ini b/Data/Sys/GameSettings/WGL.ini index f75d30a080..d4e5e2ad5e 100644 --- a/Data/Sys/GameSettings/WGL.ini +++ b/Data/Sys/GameSettings/WGL.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WHF.ini b/Data/Sys/GameSettings/WHF.ini index 11be1d2ba1..753e49fbed 100644 --- a/Data/Sys/GameSettings/WHF.ini +++ b/Data/Sys/GameSettings/WHF.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WHP.ini b/Data/Sys/GameSettings/WHP.ini index 853f4b5b56..984a9ce4a4 100644 --- a/Data/Sys/GameSettings/WHP.ini +++ b/Data/Sys/GameSettings/WHP.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WHU.ini b/Data/Sys/GameSettings/WHU.ini index b6b526cf9e..6a5c991ff3 100644 --- a/Data/Sys/GameSettings/WHU.ini +++ b/Data/Sys/GameSettings/WHU.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WIB.ini b/Data/Sys/GameSettings/WIB.ini index 721747ff28..dffda3bc1e 100644 --- a/Data/Sys/GameSettings/WIB.ini +++ b/Data/Sys/GameSettings/WIB.ini @@ -20,5 +20,6 @@ EmulationIssues = Low FPS with OpenGL, crashes with Direct3D [Video] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WJA.ini b/Data/Sys/GameSettings/WJA.ini index 1a2e059f5f..11ba53818d 100644 --- a/Data/Sys/GameSettings/WJA.ini +++ b/Data/Sys/GameSettings/WJA.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WKD.ini b/Data/Sys/GameSettings/WKD.ini index 7ba6b434da..51418fd98f 100644 --- a/Data/Sys/GameSettings/WKD.ini +++ b/Data/Sys/GameSettings/WKD.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WLE.ini b/Data/Sys/GameSettings/WLE.ini index 40f63b3962..751bf2774b 100644 --- a/Data/Sys/GameSettings/WLE.ini +++ b/Data/Sys/GameSettings/WLE.ini @@ -11,5 +11,6 @@ EmulationIssues = [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WLN.ini b/Data/Sys/GameSettings/WLN.ini index b499ca3000..2dccbd4ec6 100644 --- a/Data/Sys/GameSettings/WLN.ini +++ b/Data/Sys/GameSettings/WLN.ini @@ -11,5 +11,6 @@ EmulationIssues = [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WLZ.ini b/Data/Sys/GameSettings/WLZ.ini index 309997c141..d97c32e269 100644 --- a/Data/Sys/GameSettings/WLZ.ini +++ b/Data/Sys/GameSettings/WLZ.ini @@ -5,7 +5,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = Needs real xfb. +EmulationIssues = EmulationStateId = 4 [OnLoad] @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WMA.ini b/Data/Sys/GameSettings/WMA.ini index 5eeb33f4b9..eb8b9d0ac5 100644 --- a/Data/Sys/GameSettings/WMA.ini +++ b/Data/Sys/GameSettings/WMA.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WMB.ini b/Data/Sys/GameSettings/WMB.ini index aaf9b2389a..9fd832d6cb 100644 --- a/Data/Sys/GameSettings/WMB.ini +++ b/Data/Sys/GameSettings/WMB.ini @@ -6,7 +6,7 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Use OpenGL and Real XFB +EmulationIssues = Use OpenGL [OnLoad] # Add memory patches to be loaded once on boot here. @@ -18,6 +18,7 @@ EmulationIssues = Use OpenGL and Real XFB # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WMG.ini b/Data/Sys/GameSettings/WMG.ini index ec5ef25405..0ae83cf76b 100644 --- a/Data/Sys/GameSettings/WMG.ini +++ b/Data/Sys/GameSettings/WMG.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WOY.ini b/Data/Sys/GameSettings/WOY.ini index 3640cca17f..aba3460e7b 100644 --- a/Data/Sys/GameSettings/WOY.ini +++ b/Data/Sys/GameSettings/WOY.ini @@ -7,5 +7,5 @@ EmulationIssues = [ActionReplay] [Gecko] [Video_Settings] -UseXFB = True -UseRealXFB = False +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WP4.ini b/Data/Sys/GameSettings/WP4.ini index 9091743774..2c0206a065 100644 --- a/Data/Sys/GameSettings/WP4.ini +++ b/Data/Sys/GameSettings/WP4.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WPU.ini b/Data/Sys/GameSettings/WPU.ini index 18395f85da..3e41efb681 100644 --- a/Data/Sys/GameSettings/WPU.ini +++ b/Data/Sys/GameSettings/WPU.ini @@ -6,6 +6,7 @@ EmulationIssues = [OnFrame] [ActionReplay] [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 0 + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WR9.ini b/Data/Sys/GameSettings/WR9.ini index 2323587565..e979207f25 100644 --- a/Data/Sys/GameSettings/WR9.ini +++ b/Data/Sys/GameSettings/WR9.ini @@ -18,7 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 512 +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WRX.ini b/Data/Sys/GameSettings/WRX.ini index 08fdc132de..465ca0be3d 100644 --- a/Data/Sys/GameSettings/WRX.ini +++ b/Data/Sys/GameSettings/WRX.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 512 + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WSR.ini b/Data/Sys/GameSettings/WSR.ini index 8162ab0bf9..f74ec24893 100644 --- a/Data/Sys/GameSettings/WSR.ini +++ b/Data/Sys/GameSettings/WSR.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WTE.ini b/Data/Sys/GameSettings/WTE.ini index f18126d2bf..2952f4e295 100644 --- a/Data/Sys/GameSettings/WTE.ini +++ b/Data/Sys/GameSettings/WTE.ini @@ -18,8 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False [Video_Hacks] EFBToTextureEnable = False +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WTU.ini b/Data/Sys/GameSettings/WTU.ini index cbc6150422..fbe9fb840e 100644 --- a/Data/Sys/GameSettings/WTU.ini +++ b/Data/Sys/GameSettings/WTU.ini @@ -18,5 +18,6 @@ EmulationStateId = 4 # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WTX.ini b/Data/Sys/GameSettings/WTX.ini index 0a49a0e8ac..f1fce49758 100644 --- a/Data/Sys/GameSettings/WTX.ini +++ b/Data/Sys/GameSettings/WTX.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = True + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WWA.ini b/Data/Sys/GameSettings/WWA.ini index c3640aeae1..78ca3e5a47 100644 --- a/Data/Sys/GameSettings/WWA.ini +++ b/Data/Sys/GameSettings/WWA.ini @@ -18,5 +18,6 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WXR.ini b/Data/Sys/GameSettings/WXR.ini index 9888fef19d..873f7d5221 100644 --- a/Data/Sys/GameSettings/WXR.ini +++ b/Data/Sys/GameSettings/WXR.ini @@ -18,6 +18,7 @@ EmulationIssues = # Add action replay cheats here. [Video_Settings] -UseXFB = True -UseRealXFB = False SafeTextureCacheColorSamples = 0 + +[Video_Hacks] +ImmediateXFBEnable = False diff --git a/Source/Core/Core/Analytics.cpp b/Source/Core/Core/Analytics.cpp index fab7275112..0a079c3e1f 100644 --- a/Source/Core/Core/Analytics.cpp +++ b/Source/Core/Core/Analytics.cpp @@ -219,13 +219,13 @@ void DolphinAnalytics::MakePerGameBuilder() builder.AddData("cfg-gfx-multisamples", g_Config.iMultisamples); builder.AddData("cfg-gfx-ssaa", g_Config.bSSAA); builder.AddData("cfg-gfx-anisotropy", g_Config.iMaxAnisotropy); - builder.AddData("cfg-gfx-realxfb", g_Config.RealXFBEnabled()); - builder.AddData("cfg-gfx-virtualxfb", g_Config.VirtualXFBEnabled()); builder.AddData("cfg-gfx-vsync", g_Config.bVSync); builder.AddData("cfg-gfx-aspect-ratio", g_Config.iAspectRatio); builder.AddData("cfg-gfx-efb-access", g_Config.bEFBAccessEnable); builder.AddData("cfg-gfx-efb-copy-format-changes", g_Config.bEFBEmulateFormatChanges); builder.AddData("cfg-gfx-efb-copy-ram", !g_Config.bSkipEFBCopyToRam); + builder.AddData("cfg-gfx-xfb-copy-ram", !g_Config.bSkipXFBCopyToRam); + builder.AddData("cfg-gfx-immediate-xfb", !g_Config.bImmediateXFB); builder.AddData("cfg-gfx-efb-copy-scaled", g_Config.bCopyEFBScaled); builder.AddData("cfg-gfx-internal-resolution", g_Config.iEFBScale); builder.AddData("cfg-gfx-tc-samples", g_Config.iSafeTextureCache_ColorSamples); diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp index 0229e8d006..f95e44a92a 100644 --- a/Source/Core/Core/Config/GraphicsSettings.cpp +++ b/Source/Core/Core/Config/GraphicsSettings.cpp @@ -26,8 +26,6 @@ const ConfigInfo GFX_ASPECT_RATIO{{System::GFX, "Settings", "AspectRatio"}, const ConfigInfo GFX_SUGGESTED_ASPECT_RATIO{{System::GFX, "Settings", "SuggestedAspectRatio"}, static_cast(ASPECT_AUTO)}; const ConfigInfo GFX_CROP{{System::GFX, "Settings", "Crop"}, false}; -const ConfigInfo GFX_USE_XFB{{System::GFX, "Settings", "UseXFB"}, false}; -const ConfigInfo GFX_USE_REAL_XFB{{System::GFX, "Settings", "UseRealXFB"}, false}; const ConfigInfo GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES{ {System::GFX, "Settings", "SafeTextureCacheColorSamples"}, 128}; const ConfigInfo GFX_SHOW_FPS{{System::GFX, "Settings", "ShowFPS"}, false}; @@ -45,6 +43,7 @@ const ConfigInfo GFX_CONVERT_HIRES_TEXTURES{{System::GFX, "Settings", "Con const ConfigInfo GFX_CACHE_HIRES_TEXTURES{{System::GFX, "Settings", "CacheHiresTextures"}, false}; const ConfigInfo GFX_DUMP_EFB_TARGET{{System::GFX, "Settings", "DumpEFBTarget"}, false}; +const ConfigInfo GFX_DUMP_XFB_TARGET{{System::GFX, "Settings", "DumpXFBTarget"}, false}; const ConfigInfo GFX_DUMP_FRAMES_AS_IMAGES{{System::GFX, "Settings", "DumpFramesAsImages"}, false}; const ConfigInfo GFX_FREE_LOOK{{System::GFX, "Settings", "FreeLook"}, false}; @@ -132,6 +131,9 @@ const ConfigInfo GFX_HACK_BBOX_PREFER_STENCIL_IMPLEMENTATION{ const ConfigInfo GFX_HACK_FORCE_PROGRESSIVE{{System::GFX, "Hacks", "ForceProgressive"}, true}; const ConfigInfo GFX_HACK_SKIP_EFB_COPY_TO_RAM{{System::GFX, "Hacks", "EFBToTextureEnable"}, true}; +const ConfigInfo GFX_HACK_SKIP_XFB_COPY_TO_RAM{{System::GFX, "Hacks", "XFBToTextureEnable"}, + true}; +const ConfigInfo GFX_HACK_IMMEDIATE_XFB{{System::GFX, "Hacks", "ImmediateXFBEnable"}, false}; const ConfigInfo GFX_HACK_COPY_EFB_ENABLED{{System::GFX, "Hacks", "EFBScaledCopy"}, true}; const ConfigInfo GFX_HACK_EFB_EMULATE_FORMAT_CHANGES{ {System::GFX, "Hacks", "EFBEmulateFormatChanges"}, false}; diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h index a50ee253c0..34a68e9489 100644 --- a/Source/Core/Core/Config/GraphicsSettings.h +++ b/Source/Core/Core/Config/GraphicsSettings.h @@ -23,8 +23,6 @@ extern const ConfigInfo GFX_WIDESCREEN_HACK; extern const ConfigInfo GFX_ASPECT_RATIO; extern const ConfigInfo GFX_SUGGESTED_ASPECT_RATIO; extern const ConfigInfo GFX_CROP; -extern const ConfigInfo GFX_USE_XFB; -extern const ConfigInfo GFX_USE_REAL_XFB; extern const ConfigInfo GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES; extern const ConfigInfo GFX_SHOW_FPS; extern const ConfigInfo GFX_SHOW_NETPLAY_PING; @@ -37,6 +35,7 @@ extern const ConfigInfo GFX_HIRES_TEXTURES; extern const ConfigInfo GFX_CONVERT_HIRES_TEXTURES; extern const ConfigInfo GFX_CACHE_HIRES_TEXTURES; extern const ConfigInfo GFX_DUMP_EFB_TARGET; +extern const ConfigInfo GFX_DUMP_XFB_TARGET; extern const ConfigInfo GFX_DUMP_FRAMES_AS_IMAGES; extern const ConfigInfo GFX_FREE_LOOK; extern const ConfigInfo GFX_USE_FFV1; @@ -100,6 +99,8 @@ extern const ConfigInfo GFX_HACK_BBOX_ENABLE; extern const ConfigInfo GFX_HACK_BBOX_PREFER_STENCIL_IMPLEMENTATION; extern const ConfigInfo GFX_HACK_FORCE_PROGRESSIVE; extern const ConfigInfo GFX_HACK_SKIP_EFB_COPY_TO_RAM; +extern const ConfigInfo GFX_HACK_SKIP_XFB_COPY_TO_RAM; +extern const ConfigInfo GFX_HACK_IMMEDIATE_XFB; extern const ConfigInfo GFX_HACK_COPY_EFB_ENABLED; extern const ConfigInfo GFX_HACK_EFB_EMULATE_FORMAT_CHANGES; extern const ConfigInfo GFX_HACK_VERTEX_ROUDING; diff --git a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp index 17ffed0b94..e6ec7c97bc 100644 --- a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp @@ -74,8 +74,6 @@ static const INIToLocationMap& GetINIToLocationMap() {{"Video_Settings", "AspectRatio"}, {Config::GFX_ASPECT_RATIO.location}}, {{"Video_Settings", "SuggestedAspectRatio"}, {Config::GFX_SUGGESTED_ASPECT_RATIO.location}}, {{"Video_Settings", "Crop"}, {Config::GFX_CROP.location}}, - {{"Video_Settings", "UseXFB"}, {Config::GFX_USE_XFB.location}}, - {{"Video_Settings", "UseRealXFB"}, {Config::GFX_USE_REAL_XFB.location}}, {{"Video_Settings", "SafeTextureCacheColorSamples"}, {Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES.location}}, {{"Video_Settings", "HiresTextures"}, {Config::GFX_HIRES_TEXTURES.location}}, @@ -109,6 +107,8 @@ static const INIToLocationMap& GetINIToLocationMap() {{"Video_Hacks", "BBoxEnable"}, {Config::GFX_HACK_BBOX_ENABLE.location}}, {{"Video_Hacks", "ForceProgressive"}, {Config::GFX_HACK_FORCE_PROGRESSIVE.location}}, {{"Video_Hacks", "EFBToTextureEnable"}, {Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM.location}}, + {{"Video_Hacks", "XFBToTextureEnable"}, {Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM.location}}, + {{"Video_Hacks", "ImmediateXFBEnable"}, {Config::GFX_HACK_IMMEDIATE_XFB.location}}, {{"Video_Hacks", "EFBScaledCopy"}, {Config::GFX_EFB_SCALE.location}}, {{"Video_Hacks", "EFBEmulateFormatChanges"}, {Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES.location}}, diff --git a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp index 0349fa6ed6..84c6a82c35 100644 --- a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp +++ b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp @@ -28,17 +28,17 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location) // Graphics.Settings Config::GFX_WIDESCREEN_HACK.location, Config::GFX_ASPECT_RATIO.location, - Config::GFX_CROP.location, Config::GFX_USE_XFB.location, Config::GFX_USE_REAL_XFB.location, - Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES.location, Config::GFX_SHOW_FPS.location, - Config::GFX_SHOW_NETPLAY_PING.location, Config::GFX_SHOW_NETPLAY_MESSAGES.location, - Config::GFX_LOG_RENDER_TIME_TO_FILE.location, Config::GFX_OVERLAY_STATS.location, - Config::GFX_OVERLAY_PROJ_STATS.location, Config::GFX_DUMP_TEXTURES.location, - Config::GFX_HIRES_TEXTURES.location, Config::GFX_CONVERT_HIRES_TEXTURES.location, - Config::GFX_CACHE_HIRES_TEXTURES.location, Config::GFX_DUMP_EFB_TARGET.location, - Config::GFX_DUMP_FRAMES_AS_IMAGES.location, Config::GFX_FREE_LOOK.location, - Config::GFX_USE_FFV1.location, Config::GFX_DUMP_FORMAT.location, - Config::GFX_DUMP_CODEC.location, Config::GFX_DUMP_PATH.location, - Config::GFX_BITRATE_KBPS.location, Config::GFX_INTERNAL_RESOLUTION_FRAME_DUMPS.location, + Config::GFX_CROP.location, Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES.location, + Config::GFX_SHOW_FPS.location, Config::GFX_SHOW_NETPLAY_PING.location, + Config::GFX_SHOW_NETPLAY_MESSAGES.location, Config::GFX_LOG_RENDER_TIME_TO_FILE.location, + Config::GFX_OVERLAY_STATS.location, Config::GFX_OVERLAY_PROJ_STATS.location, + Config::GFX_DUMP_TEXTURES.location, Config::GFX_HIRES_TEXTURES.location, + Config::GFX_CONVERT_HIRES_TEXTURES.location, Config::GFX_CACHE_HIRES_TEXTURES.location, + Config::GFX_DUMP_EFB_TARGET.location, Config::GFX_DUMP_FRAMES_AS_IMAGES.location, + Config::GFX_FREE_LOOK.location, Config::GFX_USE_FFV1.location, + Config::GFX_DUMP_FORMAT.location, Config::GFX_DUMP_CODEC.location, + Config::GFX_DUMP_PATH.location, Config::GFX_BITRATE_KBPS.location, + Config::GFX_INTERNAL_RESOLUTION_FRAME_DUMPS.location, Config::GFX_ENABLE_GPU_TEXTURE_DECODING.location, Config::GFX_ENABLE_PIXEL_LIGHTING.location, Config::GFX_FAST_DEPTH_CALC.location, Config::GFX_MSAA.location, Config::GFX_SSAA.location, Config::GFX_EFB_SCALE.location, Config::GFX_TEXFMT_OVERLAY_ENABLE.location, @@ -73,6 +73,7 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location) Config::GFX_HACK_EFB_ACCESS_ENABLE.location, Config::GFX_HACK_BBOX_ENABLE.location, Config::GFX_HACK_BBOX_PREFER_STENCIL_IMPLEMENTATION.location, Config::GFX_HACK_FORCE_PROGRESSIVE.location, Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM.location, + Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM.location, Config::GFX_HACK_IMMEDIATE_XFB.location, Config::GFX_HACK_COPY_EFB_ENABLED.location, Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES.location, Config::GFX_HACK_VERTEX_ROUDING.location, diff --git a/Source/Core/Core/ConfigLoaders/MovieConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/MovieConfigLoader.cpp index edfea3919e..3585df4cc3 100644 --- a/Source/Core/Core/ConfigLoaders/MovieConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/MovieConfigLoader.cpp @@ -39,10 +39,10 @@ static void LoadFromDTM(Config::Layer* config_layer, Movie::DTMHeader* dtm) else config_layer->Set(Config::MAIN_GC_LANGUAGE, static_cast(dtm->language)); - config_layer->Set(Config::GFX_USE_XFB, dtm->bUseXFB); - config_layer->Set(Config::GFX_USE_REAL_XFB, dtm->bUseRealXFB); config_layer->Set(Config::GFX_HACK_EFB_ACCESS_ENABLE, dtm->bEFBAccessEnable); config_layer->Set(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, dtm->bSkipEFBCopyToRam); + config_layer->Set(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, dtm->bSkipXFBCopyToRam); + config_layer->Set(Config::GFX_HACK_IMMEDIATE_XFB, dtm->bImmediateXFB); config_layer->Set(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES, dtm->bEFBEmulateFormatChanges); } @@ -62,10 +62,10 @@ void SaveToDTM(Movie::DTMHeader* dtm) else dtm->language = Config::Get(Config::MAIN_GC_LANGUAGE); - dtm->bUseXFB = Config::Get(Config::GFX_USE_XFB); - dtm->bUseRealXFB = Config::Get(Config::GFX_USE_REAL_XFB); dtm->bEFBAccessEnable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE); dtm->bSkipEFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM); + dtm->bSkipXFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM); + dtm->bImmediateXFB = Config::Get(Config::GFX_HACK_IMMEDIATE_XFB); dtm->bEFBEmulateFormatChanges = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES); // This never used the regular config diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index d70d9ff712..a081d6e883 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -393,7 +393,7 @@ static void CpuThread() s_is_started = false; if (!_CoreParameter.bCPUThread) - g_video_backend->Video_Cleanup(); + g_video_backend->Video_CleanupShared(); if (_CoreParameter.bFastmem) EMM::UninstallExceptionHandler(); @@ -445,7 +445,7 @@ static void FifoPlayerThread() } if (!_CoreParameter.bCPUThread) - g_video_backend->Video_Cleanup(); + g_video_backend->Video_CleanupShared(); } // Initialize and create emulation thread @@ -654,7 +654,7 @@ static void EmuThread(std::unique_ptr boot) INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str()); if (core_parameter.bCPUThread) - g_video_backend->Video_Cleanup(); + g_video_backend->Video_CleanupShared(); // If we shut down normally, the stop message does not need to be triggered. stop_message_guard.Dismiss(); diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp index af693688f8..9b3d03d69a 100644 --- a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp +++ b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp @@ -72,6 +72,11 @@ FifoDataFile::FifoDataFile() = default; FifoDataFile::~FifoDataFile() = default; +bool FifoDataFile::ShouldGenerateFakeVIUpdates() const +{ + return true; +} + bool FifoDataFile::HasBrokenEFBCopies() const { return m_Version < 2; diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.h b/Source/Core/Core/FifoPlayer/FifoDataFile.h index f57f2fcf4a..a3825ffd2c 100644 --- a/Source/Core/Core/FifoPlayer/FifoDataFile.h +++ b/Source/Core/Core/FifoPlayer/FifoDataFile.h @@ -60,6 +60,7 @@ public: void SetIsWii(bool isWii); bool GetIsWii() const; bool HasBrokenEFBCopies() const; + bool ShouldGenerateFakeVIUpdates() const; u32* GetBPMem() { return m_BPMem; } u32* GetCPMem() { return m_CPMem; } diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index f84b783e68..32d0c0871c 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -162,6 +162,16 @@ std::unique_ptr FifoPlayer::GetCPUCore() return std::make_unique(this); } +bool FifoPlayer::IsRunningWithFakeVideoInterfaceUpdates() const +{ + if (!m_File || m_File->GetFrameCount() == 0) + { + return false; + } + + return m_File->ShouldGenerateFakeVIUpdates(); +} + u32 FifoPlayer::GetFrameObjectCount() const { if (m_CurrentFrame < m_FrameInfo.size()) diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index b291415ead..b2db00cb0f 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -94,6 +94,8 @@ public: void SetFrameWrittenCallback(CallbackFunc callback) { m_FrameWrittenCb = callback; } static FifoPlayer& GetInstance(); + bool IsRunningWithFakeVideoInterfaceUpdates() const; + private: class CPUCore; diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index d02a9be81d..46575ed2de 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -18,6 +18,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/FifoPlayer/FifoPlayer.h" #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/SI/SI.h" @@ -549,8 +550,9 @@ float GetAspectRatio() // 5. Calculate the final ratio and scale to 4:3 float ratio = horizontal_active_ratio / vertical_active_ratio; - if (std::isnormal( - ratio)) // Check we have a sane ratio and haven't propagated any infs/nans/zeros + bool running_fifo_log = FifoPlayer::GetInstance().IsRunningWithFakeVideoInterfaceUpdates(); + if (std::isnormal(ratio) && // Check we have a sane ratio without any infs/nans/zeros + !running_fifo_log) // we don't know the correct ratio for fifos return ratio * (4.0f / 3.0f); // Scale to 4:3 else return (4.0f / 3.0f); // VI isn't initialized correctly, just return 4:3 instead @@ -775,4 +777,44 @@ void Update(u64 ticks) UpdateInterrupts(); } +// Create a fake VI mode for a fifolog +void FakeVIUpdate(u32 xfb_address, u32 fb_width, u32 fb_height) +{ + u32 fb_stride = fb_width; + + bool interlaced = fb_height > 480 / 2; + if (interlaced) + { + fb_height = fb_height / 2; + fb_stride = fb_stride * 2; + } + + m_XFBInfoTop.POFF = 1; + m_XFBInfoBottom.POFF = 1; + m_VerticalTimingRegister.ACV = fb_height; + m_VerticalTimingRegister.EQU = 6; + m_VBlankTimingOdd.PRB = 502 - fb_height * 2; + m_VBlankTimingOdd.PSB = 5; + m_VBlankTimingEven.PRB = 503 - fb_height * 2; + m_VBlankTimingEven.PSB = 4; + m_PictureConfiguration.WPL = fb_width / 16; + m_PictureConfiguration.STD = fb_stride / 16; + + UpdateParameters(); + + u32 total_halflines = GetHalfLinesPerEvenField() + GetHalfLinesPerOddField(); + + if ((s_half_line_count - s_even_field_first_hl) % total_halflines < + (s_half_line_count - s_odd_field_first_hl) % total_halflines) + { + // Even/Bottom field is next. + m_XFBInfoBottom.FBB = interlaced ? (xfb_address + fb_width * 2) >> 5 : xfb_address >> 5; + } + else + { + // Odd/Top field is next + m_XFBInfoTop.FBB = (xfb_address >> 5); + } +} + } // namespace diff --git a/Source/Core/Core/HW/VideoInterface.h b/Source/Core/Core/HW/VideoInterface.h index 6d5a07edf9..7f0ebf8400 100644 --- a/Source/Core/Core/HW/VideoInterface.h +++ b/Source/Core/Core/HW/VideoInterface.h @@ -373,4 +373,7 @@ u32 GetTicksPerField(); // result by 1.33333.. float GetAspectRatio(); +// Create a fake VI mode for a fifolog +void FakeVIUpdate(u32 xfb_address, u32 fb_width, u32 fb_height); + } // namespace VideoInterface diff --git a/Source/Core/Core/HotkeyManager.cpp b/Source/Core/Core/HotkeyManager.cpp index ed586e1c7c..d989627ad1 100644 --- a/Source/Core/Core/HotkeyManager.cpp +++ b/Source/Core/Core/HotkeyManager.cpp @@ -72,6 +72,8 @@ const std::string hotkey_labels[] = { _trans("Toggle Crop"), _trans("Toggle Aspect Ratio"), _trans("Toggle EFB Copies"), + _trans("Toggle XFB Copies"), + _trans("Toggle XFB Immediate Mode"), _trans("Toggle Fog"), _trans("Toggle Texture Dumping"), _trans("Toggle Custom Textures"), diff --git a/Source/Core/Core/HotkeyManager.h b/Source/Core/Core/HotkeyManager.h index f9b4dabaf5..f8cc2bdc66 100644 --- a/Source/Core/Core/HotkeyManager.h +++ b/Source/Core/Core/HotkeyManager.h @@ -70,6 +70,8 @@ enum Hotkey HK_TOGGLE_CROP, HK_TOGGLE_AR, HK_TOGGLE_EFBCOPIES, + HK_TOGGLE_XFBCOPIES, + HK_TOGGLE_IMMEDIATE_XFB, HK_TOGGLE_FOG, HK_TOGGLE_DUMPTEXTURES, HK_TOGGLE_TEXTURES, diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 3bdcc9b13d..75bf23ee43 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -1367,9 +1367,9 @@ void SetGraphicsConfig() { g_Config.bEFBAccessEnable = tmpHeader.bEFBAccessEnable; g_Config.bSkipEFBCopyToRam = tmpHeader.bSkipEFBCopyToRam; + g_Config.bSkipXFBCopyToRam = tmpHeader.bSkipXFBCopyToRam; + g_Config.bImmediateXFB = tmpHeader.bImmediateXFB; g_Config.bEFBEmulateFormatChanges = tmpHeader.bEFBEmulateFormatChanges; - g_Config.bUseXFB = tmpHeader.bUseXFB; - g_Config.bUseRealXFB = tmpHeader.bUseRealXFB; } // NOTE: EmuThread / Host Thread diff --git a/Source/Core/Core/Movie.h b/Source/Core/Core/Movie.h index 343790ccb3..e369c5891a 100644 --- a/Source/Core/Core/Movie.h +++ b/Source/Core/Core/Movie.h @@ -87,10 +87,10 @@ struct DTMHeader bool bEFBAccessEnable; bool bEFBCopyEnable; bool bSkipEFBCopyToRam; + bool bSkipXFBCopyToRam; + bool bImmediateXFB; bool bEFBCopyCacheEnable; bool bEFBEmulateFormatChanges; - bool bUseXFB; - bool bUseRealXFB; u8 memcards; // Memcards inserted (from least to most significant, the bits are slot A and B) bool bClearSave; // Create a new memory card when playing back a movie if true u8 bongos; // Bongos plugged in (from least to most significant, the bits are ports 1-4) diff --git a/Source/Core/DolphinQt2/Config/Graphics/HacksWidget.cpp b/Source/Core/DolphinQt2/Config/Graphics/HacksWidget.cpp index 3690a43161..ad30644749 100644 --- a/Source/Core/DolphinQt2/Config/Graphics/HacksWidget.cpp +++ b/Source/Core/DolphinQt2/Config/Graphics/HacksWidget.cpp @@ -20,7 +20,6 @@ HacksWidget::HacksWidget(GraphicsWindow* parent) : GraphicsWidget(parent) CreateWidgets(); LoadSettings(); ConnectWidgets(); - OnXFBToggled(); AddDescriptions(); } @@ -68,13 +67,12 @@ void HacksWidget::CreateWidgets() auto* xfb_layout = new QGridLayout(); xfb_box->setLayout(xfb_layout); - m_disable_xfb = new GraphicsBool(tr("Disable"), Config::GFX_USE_XFB, true); - m_real_xfb = new GraphicsBoolEx(tr("Real"), Config::GFX_USE_REAL_XFB, false); - m_virtual_xfb = new GraphicsBoolEx(tr("Virtual"), Config::GFX_USE_REAL_XFB, true); + m_store_xfb_copies = new GraphicsBool(tr("Store XFB Copies to Texture Only"), + Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM); + m_immediate_xfb = new GraphicsBool(tr("Immediately Present XFB"), Config::GFX_HACK_IMMEDIATE_XFB); + + xfb_layout->addWidget(m_store_xfb_copies, 1, 0); - xfb_layout->addWidget(m_disable_xfb, 0, 0); - xfb_layout->addWidget(m_virtual_xfb, 0, 1); - xfb_layout->addWidget(m_real_xfb, 0, 2); // Other auto* other_box = new QGroupBox(tr("Other")); auto* other_layout = new QGridLayout(); @@ -101,16 +99,9 @@ void HacksWidget::CreateWidgets() void HacksWidget::ConnectWidgets() { - connect(m_disable_xfb, &QCheckBox::toggled, this, &HacksWidget::OnXFBToggled); connect(m_accuracy, &QSlider::valueChanged, [this](int) { SaveSettings(); }); } -void HacksWidget::OnXFBToggled() -{ - m_real_xfb->setEnabled(!m_disable_xfb->isChecked()); - m_virtual_xfb->setEnabled(!m_disable_xfb->isChecked()); -} - void HacksWidget::LoadSettings() { auto samples = Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES); @@ -179,20 +170,18 @@ void HacksWidget::AddDescriptions() "from RAM.\nLower accuracies cause in-game text to appear garbled in certain " "games.\n\nIf unsure, use the rightmost value."); - static const char* TR_DISABLE_XFB_DESCRIPTION = QT_TR_NOOP( - "Disable any XFB emulation.\nSpeeds up emulation a lot but causes heavy glitches in many " - "games " - "which rely on them (especially homebrew applications).\n\nIf unsure, leave this checked."); - static const char* TR_VIRTUAL_XFB_DESCRIPTION = QT_TR_NOOP( - "Emulate XFBs using GPU texture objects.\nFixes many games which don't work without XFB " - "emulation while not being as slow as real XFB emulation. However, it may still fail for " - "a lot " - "of other games (especially homebrew applications).\n\nIf unsure, leave this checked."); + static const char* TR_STORE_XFB_TO_TEXTURE_DESCRIPTION = QT_TR_NOOP( + "Stores XFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects " + "in a small number of games that need to readback from memory.\n\nEnabled = XFB Copies to " + "Texture\nDisabled = XFB Copies to RAM " + "(and Texture)\n\nIf unsure, leave this checked."); - static const char* TR_REAL_XFB_DESCRIPTION = - QT_TR_NOOP("Emulate XFBs accurately.\nSlows down emulation a lot and prohibits " - "high-resolution rendering but is necessary to emulate a number of games " - "properly.\n\nIf unsure, check virtual XFB emulation instead."); + static const char* TR_IMMEDIATE_XFB_DESCRIPTION = + QT_TR_NOOP("Displays the XFB copies as soon as they are created, without waiting for " + "scanout. Can cause graphical defects " + "in some games if the game doesn't expect all XFB copies to be displayed. " + "However, turning this setting on reduces latency." + "\n\nIf unsure, leave this unchecked."); static const char* TR_GPU_DECODING_DESCRIPTION = QT_TR_NOOP("Enables texture decoding using the GPU instead of the CPU. This may result in " @@ -215,9 +204,8 @@ void HacksWidget::AddDescriptions() AddDescription(m_ignore_format_changes, TR_IGNORE_FORMAT_CHANGE_DESCRIPTION); AddDescription(m_store_efb_copies, TR_STORE_EFB_TO_TEXTURE_DESCRIPTION); AddDescription(m_accuracy, TR_ACCUARCY_DESCRIPTION); - AddDescription(m_disable_xfb, TR_DISABLE_XFB_DESCRIPTION); - AddDescription(m_virtual_xfb, TR_VIRTUAL_XFB_DESCRIPTION); - AddDescription(m_real_xfb, TR_REAL_XFB_DESCRIPTION); + AddDescription(m_store_xfb_copies, TR_STORE_XFB_TO_TEXTURE_DESCRIPTION); + AddDescription(m_immediate_xfb, TR_STORE_XFB_TO_TEXTURE_DESCRIPTION); AddDescription(m_gpu_texture_decoding, TR_GPU_DECODING_DESCRIPTION); AddDescription(m_fast_depth_calculation, TR_FAST_DEPTH_CALC_DESCRIPTION); AddDescription(m_disable_bounding_box, TR_DISABLE_BOUNDINGBOX_DESCRIPTION); diff --git a/Source/Core/DolphinQt2/Config/Graphics/HacksWidget.h b/Source/Core/DolphinQt2/Config/Graphics/HacksWidget.h index d652a10b3f..d612a6adf4 100644 --- a/Source/Core/DolphinQt2/Config/Graphics/HacksWidget.h +++ b/Source/Core/DolphinQt2/Config/Graphics/HacksWidget.h @@ -21,8 +21,6 @@ private: void LoadSettings() override; void SaveSettings() override; - void OnXFBToggled(); - // EFB QCheckBox* m_skip_efb_cpu; QCheckBox* m_ignore_format_changes; @@ -33,9 +31,8 @@ private: QCheckBox* m_gpu_texture_decoding; // External Framebuffer - QCheckBox* m_disable_xfb; - QRadioButton* m_virtual_xfb; - QRadioButton* m_real_xfb; + QCheckBox* m_store_xfb_copies; + QCheckBox* m_immediate_xfb; // Other QCheckBox* m_fast_depth_calculation; diff --git a/Source/Core/DolphinQt2/Config/Graphics/SoftwareRendererWidget.cpp b/Source/Core/DolphinQt2/Config/Graphics/SoftwareRendererWidget.cpp index 65cd96b2c5..24e0d77836 100644 --- a/Source/Core/DolphinQt2/Config/Graphics/SoftwareRendererWidget.cpp +++ b/Source/Core/DolphinQt2/Config/Graphics/SoftwareRendererWidget.cpp @@ -38,12 +38,10 @@ void SoftwareRendererWidget::CreateWidgets() auto* rendering_box = new QGroupBox(tr("Rendering")); auto* rendering_layout = new QGridLayout(); m_backend_combo = new QComboBox(); - m_bypass_xfb = new GraphicsBool(tr("Bypass XFB"), Config::GFX_USE_XFB, true); rendering_box->setLayout(rendering_layout); rendering_layout->addWidget(new QLabel(tr("Backend:")), 1, 1); rendering_layout->addWidget(m_backend_combo, 1, 2); - rendering_layout->addWidget(m_bypass_xfb, 2, 1); for (const auto& backend : g_available_video_backends) m_backend_combo->addItem(tr(backend->GetDisplayName().c_str())); @@ -156,11 +154,6 @@ void SoftwareRendererWidget::AddDescriptions() "backend, so for the best emulation experience it's recommended to try both and " "choose the one that's less problematic.\n\nIf unsure, select OpenGL."); - static const char* TR_BYPASS_XFB_DESCRIPTION = QT_TR_NOOP( - "Disable any XFB emulation.\nSpeeds up emulation a lot but causes heavy glitches in many " - "games " - "which rely on them (especially homebrew applications).\n\nIf unsure, leave this checked."); - static const char* TR_SHOW_STATISTICS_DESCRIPTION = QT_TR_NOOP("Show various rendering statistics.\n\nIf unsure, leave this unchecked."); @@ -169,7 +162,6 @@ void SoftwareRendererWidget::AddDescriptions() "this unchecked."); AddDescription(m_backend_combo, TR_BACKEND_DESCRIPTION); - AddDescription(m_bypass_xfb, TR_BYPASS_XFB_DESCRIPTION); AddDescription(m_enable_statistics, TR_SHOW_STATISTICS_DESCRIPTION); AddDescription(m_dump_textures, TR_DUMP_TEXTURES_DESCRIPTION); } diff --git a/Source/Core/DolphinQt2/Config/Graphics/SoftwareRendererWidget.h b/Source/Core/DolphinQt2/Config/Graphics/SoftwareRendererWidget.h index 61b6130d4c..19d0918a63 100644 --- a/Source/Core/DolphinQt2/Config/Graphics/SoftwareRendererWidget.h +++ b/Source/Core/DolphinQt2/Config/Graphics/SoftwareRendererWidget.h @@ -29,7 +29,6 @@ private: void AddDescriptions(); QComboBox* m_backend_combo; - QCheckBox* m_bypass_xfb; QCheckBox* m_enable_statistics; QCheckBox* m_dump_textures; QCheckBox* m_dump_objects; diff --git a/Source/Core/DolphinQt2/HotkeyScheduler.cpp b/Source/Core/DolphinQt2/HotkeyScheduler.cpp index e3aa7750c9..547e4676de 100644 --- a/Source/Core/DolphinQt2/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt2/HotkeyScheduler.cpp @@ -224,6 +224,10 @@ void HotkeyScheduler::Run() g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; if (IsHotkey(HK_TOGGLE_EFBCOPIES)) g_Config.bSkipEFBCopyToRam = !g_Config.bSkipEFBCopyToRam; + if (IsHotkey(HK_TOGGLE_XFBCOPIES)) + g_Config.bSkipXFBCopyToRam = !g_Config.bSkipXFBCopyToRam; + if (IsHotkey(HK_TOGGLE_IMMEDIATE_XFB)) + g_Config.bImmediateXFB = !g_Config.bImmediateXFB; if (IsHotkey(HK_TOGGLE_FOG)) g_Config.bDisableFog = !g_Config.bDisableFog; if (IsHotkey(HK_TOGGLE_DUMPTEXTURES)) diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index 6a1c3a0c53..1f89306a13 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -1484,6 +1484,20 @@ void CFrame::ParseHotkeys() Config::SetCurrent(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM)); } + if (IsHotkey(HK_TOGGLE_XFBCOPIES)) + { + OSDChoice = 6; + // Toggle XFB copies between XFB2RAM and XFB2Texture + Config::SetCurrent(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, + !Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM)); + } + if (IsHotkey(HK_TOGGLE_IMMEDIATE_XFB)) + { + OSDChoice = 6; + // Toggle immediate present of xfb + Config::SetCurrent(Config::GFX_HACK_IMMEDIATE_XFB, + !Config::Get(Config::GFX_HACK_IMMEDIATE_XFB)); + } if (IsHotkey(HK_TOGGLE_FOG)) { OSDChoice = 4; diff --git a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp index af1ab0485a..76601ca2a9 100644 --- a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp +++ b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp @@ -77,10 +77,6 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std label_backend->Disable(); choice_backend->Disable(); } - - // xfb - szr_rendering->Add( - new SettingCheckBox(page_general, _("Bypass XFB"), "", Config::GFX_USE_XFB, true)); } // - info diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index f94a4419c8..dad285a385 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -201,6 +201,17 @@ static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE( "Stores EFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects " "in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to RAM " "(and Texture)\n\nIf unsure, leave this checked."); +static wxString skip_xfb_copy_to_ram_desc = wxTRANSLATE( + "Stores XFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects " + "in a small number of games that need to readback from memory.\n\nEnabled = XFB Copies to " + "Texture\nDisabled = XFB Copies to RAM " + "(and Texture)\n\nIf unsure, leave this checked."); +static wxString immediate_xfb_desc = + wxTRANSLATE("Displays the XFB copies as soon as they are created, without waiting for scanout. " + "Can cause graphical defects " + "in some games if the game doesn't expect all XFB copies to be displayed. However, " + "turning this setting on reduces latency." + "\n\nIf unsure, leave this unchecked."); static wxString stc_desc = wxTRANSLATE("The \"Safe\" setting eliminates the likelihood of the GPU missing texture updates " "from RAM.\nLower accuracies cause in-game text to appear garbled in certain " @@ -229,17 +240,6 @@ static wxString show_netplay_messages_desc = static wxString texfmt_desc = wxTRANSLATE("Modify textures to show the format they're encoded in. Needs an emulation reset " "in most cases.\n\nIf unsure, leave this unchecked."); -static wxString xfb_desc = wxTRANSLATE( - "Disable any XFB emulation.\nSpeeds up emulation a lot but causes heavy glitches in many games " - "which rely on them (especially homebrew applications).\n\nIf unsure, leave this checked."); -static wxString xfb_virtual_desc = wxTRANSLATE( - "Emulate XFBs using GPU texture objects.\nFixes many games which don't work without XFB " - "emulation while not being as slow as real XFB emulation. However, it may still fail for a lot " - "of other games (especially homebrew applications).\n\nIf unsure, leave this checked."); -static wxString xfb_real_desc = - wxTRANSLATE("Emulate XFBs accurately.\nSlows down emulation a lot and prohibits " - "high-resolution rendering but is necessary to emulate a number of games " - "properly.\n\nIf unsure, check virtual XFB emulation instead."); static wxString dump_textures_desc = wxTRANSLATE("Dump decoded game textures to User/Dump/Textures//.\n\nIf unsure, leave " "this unchecked."); @@ -250,6 +250,8 @@ static wxString cache_hires_textures_desc = "more RAM but fixes possible stuttering.\n\nIf unsure, leave this unchecked."); static wxString dump_efb_desc = wxTRANSLATE( "Dump the contents of EFB copies to User/Dump/Textures/.\n\nIf unsure, leave this unchecked."); +static wxString dump_xfb_desc = wxTRANSLATE( + "Dump the contents of XFB copies to User/Dump/Textures/.\n\nIf unsure, leave this unchecked."); static wxString internal_resolution_frame_dumping_desc = wxTRANSLATE( "Create frame dumps and screenshots at the internal resolution of the renderer, rather than " "the size of the window it is displayed within. If the aspect ratio is widescreen, the output " @@ -750,20 +752,16 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title) wxStaticBoxSizer* const group_xfb = new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("External Frame Buffer (XFB)")); - SettingCheckBox* disable_xfb = CreateCheckBox( - page_hacks, _("Disable"), wxGetTranslation(xfb_desc), Config::GFX_USE_XFB, true); - virtual_xfb = CreateRadioButton(page_hacks, _("Virtual"), wxGetTranslation(xfb_virtual_desc), - Config::GFX_USE_REAL_XFB, true, wxRB_GROUP); - real_xfb = CreateRadioButton(page_hacks, _("Real"), wxGetTranslation(xfb_real_desc), - Config::GFX_USE_REAL_XFB); + group_xfb->Add(CreateCheckBox(page_hacks, _("Store XFB Copies to Texture Only"), + wxGetTranslation(skip_xfb_copy_to_ram_desc), + Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM), + 0, wxLEFT | wxRIGHT, space5); + group_xfb->AddSpacer(space5); - wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); - szr->Add(disable_xfb, 0, wxALIGN_CENTER_VERTICAL); - szr->AddStretchSpacer(1); - szr->Add(virtual_xfb, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5); - szr->Add(real_xfb, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5); - - group_xfb->Add(szr, 1, wxEXPAND | wxLEFT | wxRIGHT, space5); + group_xfb->Add(CreateCheckBox(page_hacks, _("Immediately Present XFB"), + wxGetTranslation(immediate_xfb_desc), + Config::GFX_HACK_IMMEDIATE_XFB), + 0, wxLEFT | wxRIGHT, space5); group_xfb->AddSpacer(space5); szr_hacks->AddSpacer(space5); @@ -855,6 +853,9 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title) szr_utility->Add(CreateCheckBox(page_advanced, _("Dump EFB Target"), wxGetTranslation(dump_efb_desc), Config::GFX_DUMP_EFB_TARGET)); + szr_utility->Add(CreateCheckBox(page_advanced, _("Dump XFB Target"), + wxGetTranslation(dump_xfb_desc), + Config::GFX_DUMP_XFB_TARGET)); szr_utility->Add(CreateCheckBox(page_advanced, _("Free Look"), wxGetTranslation(free_look_desc), Config::GFX_FREE_LOOK)); #if defined(HAVE_FFMPEG) @@ -1053,10 +1054,6 @@ void VideoConfigDiag::OnUpdateUI(wxUpdateUIEvent& ev) choice_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); text_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); - // XFB - virtual_xfb->Enable(vconfig.bUseXFB); - real_xfb->Enable(vconfig.bUseXFB); - // custom textures cache_hires_textures->Enable(vconfig.bHiresTextures); diff --git a/Source/Core/VideoBackends/D3D/CMakeLists.txt b/Source/Core/VideoBackends/D3D/CMakeLists.txt index 953f8737e5..3811ce6a0d 100644 --- a/Source/Core/VideoBackends/D3D/CMakeLists.txt +++ b/Source/Core/VideoBackends/D3D/CMakeLists.txt @@ -38,8 +38,6 @@ set(SRCS VertexShaderCache.cpp VertexShaderCache.h VideoBackend.h - XFBEncoder.cpp - XFBEncoder.h ) set(LIBS diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index e766387de8..50c8ea0fcd 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -52,11 +52,9 @@ - - @@ -73,12 +71,10 @@ - - diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index cc05377bda..f544ae67db 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -48,9 +48,6 @@ Render - - Render - Render @@ -60,9 +57,6 @@ Render - - Render - Render @@ -108,9 +102,6 @@ Render - - Render - Render @@ -120,9 +111,6 @@ Render - - Render - Render diff --git a/Source/Core/VideoBackends/D3D/DXTexture.cpp b/Source/Core/VideoBackends/D3D/DXTexture.cpp index 1ac52e76b2..5f7a4e39eb 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.cpp +++ b/Source/Core/VideoBackends/D3D/DXTexture.cpp @@ -80,6 +80,7 @@ DXTexture::DXTexture(const TextureConfig& tex_config) : AbstractTexture(tex_conf DXTexture::~DXTexture() { m_texture->Release(); + SAFE_RELEASE(m_staging_texture); } D3DTexture2D* DXTexture::GetRawTexIdentifier() const @@ -92,48 +93,72 @@ void DXTexture::Bind(unsigned int stage) D3D::stateman->SetTexture(stage, m_texture->GetSRV()); } -bool DXTexture::Save(const std::string& filename, unsigned int level) +std::optional DXTexture::MapFullImpl() { - // We can't dump compressed textures currently (it would mean drawing them to a RGBA8 - // framebuffer, and saving that). TextureCache does not call Save for custom textures - // anyway, so this is fine for now. - _assert_(m_config.format == AbstractTextureFormat::RGBA8); + CD3D11_TEXTURE2D_DESC staging_texture_desc(DXGI_FORMAT_R8G8B8A8_UNORM, m_config.width, + m_config.height, 1, 1, 0, D3D11_USAGE_STAGING, + D3D11_CPU_ACCESS_READ); - // Create a staging/readback texture with the dimensions of the specified mip level. - u32 mip_width = std::max(m_config.width >> level, 1u); - u32 mip_height = std::max(m_config.height >> level, 1u); - CD3D11_TEXTURE2D_DESC staging_texture_desc(DXGI_FORMAT_R8G8B8A8_UNORM, mip_width, mip_height, 1, - 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); - - ID3D11Texture2D* staging_texture; - HRESULT hr = D3D::device->CreateTexture2D(&staging_texture_desc, nullptr, &staging_texture); + HRESULT hr = D3D::device->CreateTexture2D(&staging_texture_desc, nullptr, &m_staging_texture); if (FAILED(hr)) { WARN_LOG(VIDEO, "Failed to create texture dumping readback texture: %X", static_cast(hr)); - return false; + return {}; } - // Copy the selected mip level to the staging texture. - CD3D11_BOX src_box(0, 0, 0, mip_width, mip_height, 1); - D3D::context->CopySubresourceRegion(staging_texture, 0, 0, 0, 0, m_texture->GetTex(), + // Copy the selected data to the staging texture + D3D::context->CopyResource(m_staging_texture, m_texture->GetTex()); + + // Map the staging texture to client memory, and encode it as a .png image. + D3D11_MAPPED_SUBRESOURCE map; + hr = D3D::context->Map(m_staging_texture, 0, D3D11_MAP_READ, 0, &map); + if (FAILED(hr)) + { + WARN_LOG(VIDEO, "Failed to map texture dumping readback texture: %X", static_cast(hr)); + return {}; + } + + return AbstractTexture::RawTextureInfo{reinterpret_cast(map.pData), map.RowPitch, + m_config.width, m_config.height}; +} + +std::optional DXTexture::MapRegionImpl(u32 level, u32 x, u32 y, + u32 width, u32 height) +{ + CD3D11_TEXTURE2D_DESC staging_texture_desc(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1, 1, 0, + D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); + + HRESULT hr = D3D::device->CreateTexture2D(&staging_texture_desc, nullptr, &m_staging_texture); + if (FAILED(hr)) + { + WARN_LOG(VIDEO, "Failed to create texture dumping readback texture: %X", static_cast(hr)); + return {}; + } + + // Copy the selected data to the staging texture + CD3D11_BOX src_box(x, y, 0, width, height, 1); + D3D::context->CopySubresourceRegion(m_staging_texture, 0, 0, 0, 0, m_texture->GetTex(), D3D11CalcSubresource(level, 0, m_config.levels), &src_box); // Map the staging texture to client memory, and encode it as a .png image. D3D11_MAPPED_SUBRESOURCE map; - hr = D3D::context->Map(staging_texture, 0, D3D11_MAP_READ, 0, &map); + hr = D3D::context->Map(m_staging_texture, 0, D3D11_MAP_READ, 0, &map); if (FAILED(hr)) { WARN_LOG(VIDEO, "Failed to map texture dumping readback texture: %X", static_cast(hr)); - staging_texture->Release(); - return false; + return {}; } - bool encode_result = - TextureToPng(reinterpret_cast(map.pData), map.RowPitch, filename, mip_width, mip_height); - D3D::context->Unmap(staging_texture, 0); - staging_texture->Release(); + return AbstractTexture::RawTextureInfo{reinterpret_cast(map.pData), map.RowPitch, + m_config.width, m_config.height}; +} - return encode_result; +void DXTexture::Unmap() +{ + if (!m_staging_texture) + return; + + D3D::context->Unmap(m_staging_texture, 0); } void DXTexture::CopyRectangleFromTexture(const AbstractTexture* source, diff --git a/Source/Core/VideoBackends/D3D/DXTexture.h b/Source/Core/VideoBackends/D3D/DXTexture.h index a57c104fa0..8dfffd38d5 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.h +++ b/Source/Core/VideoBackends/D3D/DXTexture.h @@ -19,7 +19,7 @@ public: ~DXTexture(); void Bind(unsigned int stage) override; - bool Save(const std::string& filename, unsigned int level) override; + void Unmap() override; void CopyRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, @@ -30,7 +30,12 @@ public: D3DTexture2D* GetRawTexIdentifier() const; private: + std::optional MapFullImpl() override; + std::optional MapRegionImpl(u32 level, u32 x, u32 y, u32 width, + u32 height) override; + D3DTexture2D* m_texture; + ID3D11Texture2D* m_staging_texture = nullptr; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp index 5853b8e849..4bd5a3fd60 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp @@ -16,12 +16,10 @@ #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/Render.h" #include "VideoBackends/D3D/VertexShaderCache.h" -#include "VideoBackends/D3D/XFBEncoder.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { -static XFBEncoder s_xfbEncoder; static bool s_integer_efb_render_target = false; FramebufferManager::Efb FramebufferManager::m_efb; @@ -282,15 +280,11 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) m_efb.resolved_color_tex = nullptr; m_efb.resolved_depth_tex = nullptr; } - - s_xfbEncoder.Init(); s_integer_efb_render_target = false; } FramebufferManager::~FramebufferManager() { - s_xfbEncoder.Shutdown(); - SAFE_RELEASE(m_efb.color_tex); SAFE_RELEASE(m_efb.color_int_rtv); SAFE_RELEASE(m_efb.color_temp_tex); @@ -304,58 +298,4 @@ FramebufferManager::~FramebufferManager() SAFE_RELEASE(m_efb.resolved_depth_tex); } -void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, - const EFBRectangle& sourceRc, float Gamma) -{ - u8* dst = Memory::GetPointer(xfbAddr); - - // The destination stride can differ from the copy region width, in which case the pixels - // outside the copy region should not be written to. - s_xfbEncoder.Encode(dst, static_cast(sourceRc.GetWidth()), fbHeight, sourceRc, Gamma); -} - -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) -{ - return std::make_unique( - D3DTexture2D::Create(target_width, target_height, - (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), - layers); -} - -std::pair FramebufferManager::GetTargetSize() const -{ - return std::make_pair(m_target_width, m_target_height); -} - -void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) -{ - // DX11's XFB decoder does not use this function. - // YUYV data is decoded in Render::Swap. -} - -void XFBSource::CopyEFB(float Gamma) -{ - g_renderer->ResetAPIState(); // reset any game specific settings - - // Copy EFB data to XFB and restore render target again - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight); - const D3D11_RECT rect = CD3D11_RECT(0, 0, texWidth, texHeight); - - D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), nullptr); - D3D::SetPointCopySampler(); - - D3D::drawShadedTexQuad( - FramebufferManager::GetEFBColorTexture()->GetSRV(), &rect, g_renderer->GetTargetWidth(), - g_renderer->GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(true), - VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), - GeometryShaderCache::GetCopyGeometryShader(), Gamma); - - FramebufferManager::BindEFBRenderTarget(); - g_renderer->RestoreAPIState(); -} - } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.h b/Source/Core/VideoBackends/D3D/FramebufferManager.h index f38a60edc0..f8767a2c5d 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.h +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.h @@ -46,17 +46,6 @@ namespace DX11 // There may be multiple XFBs in GameCube RAM. This is the maximum number to // virtualize. -struct XFBSource : public XFBSourceBase -{ - XFBSource(D3DTexture2D* _tex, int slices) : tex(_tex), m_slices(slices) {} - ~XFBSource() { tex->Release(); } - void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override; - void CopyEFB(float Gamma) override; - - D3DTexture2D* const tex; - const int m_slices; -}; - class FramebufferManager : public FramebufferManagerBase { public: @@ -80,14 +69,6 @@ public: static void BindEFBRenderTarget(bool bind_depth = true); private: - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override; - std::pair GetTargetSize() const override; - - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma) override; - static struct Efb { D3DTexture2D* color_tex; diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index 9b24783f6a..4fcce4ef03 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -26,6 +26,8 @@ struct EFBEncodeParams s32 SrcTop; u32 DestWidth; u32 ScaleFactor; + float y_scale; + u32 padding[3]; }; PSTextureEncoder::PSTextureEncoder() @@ -41,8 +43,11 @@ void PSTextureEncoder::Init() HRESULT hr; // Create output texture RGBA format - D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM, EFB_WIDTH * 4, - EFB_HEIGHT / 4, 1, 1, D3D11_BIND_RENDER_TARGET); + // TODO: This Texture is overly large and parts of it are unused + // EFB2RAM copies use max (EFB_WIDTH * 4) by (EFB_HEIGHT / 4) + // XFB2RAM copies use max (EFB_WIDTH / 2) by (EFB_HEIGHT) + D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM, EFB_WIDTH * 4, 1024, + 1, 1, D3D11_BIND_RENDER_TARGET); hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out); CHECK(SUCCEEDED(hr), "create efb encode output texture"); D3D::SetDebugObjectName(m_out, "efb encoder output texture"); @@ -124,6 +129,7 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w encode_params.SrcTop = src_rect.top; encode_params.DestWidth = native_width; encode_params.ScaleFactor = scale_by_half ? 2 : 1; + encode_params.y_scale = params.y_scale; D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, &encode_params, 0, 0); D3D::stateman->SetPixelConstants(m_encodeParams); @@ -131,7 +137,7 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w // TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more // complex down filtering to average all pixels and produce the correct result. // Also, box filtering won't be correct for anything other than 1x IR - if (scale_by_half || g_renderer->GetEFBScale() != 1) + if (scale_by_half || g_renderer->GetEFBScale() != 1 || params.y_scale > 1.0f) D3D::SetLinearCopySampler(); else D3D::SetPointCopySampler(); diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 5fce3ab961..11bbea61c2 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -24,10 +24,10 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DUtil.h" +#include "VideoBackends/D3D/DXTexture.h" #include "VideoBackends/D3D/FramebufferManager.h" #include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/PixelShaderCache.h" -#include "VideoBackends/D3D/Television.h" #include "VideoBackends/D3D/TextureCache.h" #include "VideoBackends/D3D/VertexShaderCache.h" @@ -39,6 +39,7 @@ #include "VideoCommon/RenderState.h" #include "VideoCommon/SamplerCommon.h" #include "VideoCommon/VideoBackendBase.h" +#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" #include "VideoCommon/XFMemory.h" @@ -66,11 +67,8 @@ struct GXPipelineState static u32 s_last_multisamples = 1; static bool s_last_stereo_mode = false; -static bool s_last_xfb_mode = false; static bool s_last_fullscreen_mode = false; -static Television s_television; - static std::array s_clear_blend_states{}; static std::array s_clear_depth_states{}; static ID3D11BlendState* s_reset_blend_state = nullptr; @@ -85,8 +83,6 @@ static StateCache s_gx_state_cache; static void SetupDeviceObjects() { - s_television.Init(); - HRESULT hr; D3D11_DEPTH_STENCIL_DESC ddesc; @@ -182,36 +178,9 @@ static void TeardownDeviceObjects() SAFE_RELEASE(s_screenshot_texture); SAFE_RELEASE(s_3d_vision_texture); - s_television.Shutdown(); - s_gx_state_cache.Clear(); } -static void CreateScreenshotTexture() -{ - // We can't render anything outside of the backbuffer anyway, so use the backbuffer size as the - // screenshot buffer size. - // This texture is released to be recreated when the window is resized in Renderer::SwapImpl. - D3D11_TEXTURE2D_DESC scrtex_desc = CD3D11_TEXTURE2D_DESC( - DXGI_FORMAT_R8G8B8A8_UNORM, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, - D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); - HRESULT hr = D3D::device->CreateTexture2D(&scrtex_desc, nullptr, &s_screenshot_texture); - CHECK(hr == S_OK, "Create screenshot staging texture"); - D3D::SetDebugObjectName(s_screenshot_texture, "staging screenshot texture"); -} - -static D3D11_BOX GetScreenshotSourceBox(const TargetRectangle& targetRc) -{ - // Since the screenshot buffer is copied back to the CPU via Map(), we can't access pixels that - // fall outside the backbuffer bounds. Therefore, when crop is enabled and the target rect is - // off-screen to the top/left, we clamp the origin at zero, as well as the bottom/right - // coordinates at the backbuffer dimensions. This will result in a rectangle that can be - // smaller than the backbuffer, but never larger. - return CD3D11_BOX(std::max(targetRc.left, 0), std::max(targetRc.top, 0), 0, - std::min(D3D::GetBackBufferWidth(), (unsigned int)targetRc.right), - std::min(D3D::GetBackBufferHeight(), (unsigned int)targetRc.bottom), 1); -} - static void Create3DVisionTexture(int width, int height) { // Create a staging texture for 3D vision with signature information in the last row. @@ -241,7 +210,6 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH { s_last_multisamples = g_ActiveConfig.iMultisamples; s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; s_last_fullscreen_mode = D3D::GetFullscreenState(); g_framebuffer_manager = std::make_unique(m_target_width, m_target_height); @@ -640,24 +608,9 @@ void Renderer::SetBlendingState(const BlendingState& state) } // This function has the final picture. We adjust the aspect ratio here. -void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, - const EFBRectangle& rc, u64 ticks, float Gamma) +void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks, + float Gamma) { - if ((!m_xfb_written && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) - { - Core::Callback_VideoCopiedToXFB(false); - return; - } - - u32 xfbCount = 0; - const XFBSourceBase* const* xfbSourceList = - FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); - if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) - { - Core::Callback_VideoCopiedToXFB(false); - return; - } - ResetAPIState(); // Prepare to copy the XFBs to our backbuffer @@ -671,90 +624,10 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, // activate linear filtering for the buffer copies D3D::SetLinearCopySampler(); + auto* xfb_texture = static_cast(texture); - if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB) - { - // TODO: Television should be used to render Virtual XFB mode as well. - D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, - (float)targetRc.GetWidth(), (float)targetRc.GetHeight()); - D3D::context->RSSetViewports(1, &vp); - - s_television.Submit(xfbAddr, fbStride, fbWidth, fbHeight); - s_television.Render(); - } - else if (g_ActiveConfig.bUseXFB) - { - // draw each xfb source - for (u32 i = 0; i < xfbCount; ++i) - { - const auto* const xfbSource = static_cast(xfbSourceList[i]); - - // use virtual xfb with offset - int xfbHeight = xfbSource->srcHeight; - int xfbWidth = xfbSource->srcWidth; - int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2); - - TargetRectangle drawRc; - drawRc.top = targetRc.top + hOffset * targetRc.GetHeight() / (s32)fbHeight; - drawRc.bottom = targetRc.top + (hOffset + xfbHeight) * targetRc.GetHeight() / (s32)fbHeight; - drawRc.left = targetRc.left + - (targetRc.GetWidth() - xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; - drawRc.right = targetRc.left + - (targetRc.GetWidth() + xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; - - // The following code disables auto stretch. Kept for reference. - // scale draw area for a 1 to 1 pixel mapping with the draw target - // float vScale = (float)fbHeight / (float)s_backbuffer_height; - // float hScale = (float)fbWidth / (float)s_backbuffer_width; - // drawRc.top *= vScale; - // drawRc.bottom *= vScale; - // drawRc.left *= hScale; - // drawRc.right *= hScale; - - TargetRectangle sourceRc; - sourceRc.left = xfbSource->sourceRc.left; - sourceRc.top = xfbSource->sourceRc.top; - sourceRc.right = xfbSource->sourceRc.right; - sourceRc.bottom = xfbSource->sourceRc.bottom; - - sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth); - - BlitScreen(sourceRc, drawRc, xfbSource->tex, xfbSource->texWidth, xfbSource->texHeight, - Gamma); - } - } - else - { - TargetRectangle sourceRc = Renderer::ConvertEFBRectangle(rc); - - // TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB - // texture as source - D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture(); - BlitScreen(sourceRc, targetRc, read_texture, GetTargetWidth(), GetTargetHeight(), Gamma); - } - - // Dump frames - if (IsFrameDumping()) - { - if (!s_screenshot_texture) - CreateScreenshotTexture(); - - D3D11_BOX source_box = GetScreenshotSourceBox(targetRc); - unsigned int source_width = source_box.right - source_box.left; - unsigned int source_height = source_box.bottom - source_box.top; - D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, - D3D::GetBackBuffer()->GetTex(), 0, &source_box); - - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); - - AVIDump::Frame state = AVIDump::FetchState(ticks); - DumpFrameData(reinterpret_cast(map.pData), source_width, source_height, map.RowPitch, - state); - FinishFrameData(); - - D3D::context->Unmap(s_screenshot_texture, 0); - } + BlitScreen(xfb_region, targetRc, xfb_texture->GetRawTexIdentifier(), + xfb_texture->GetConfig().width, xfb_texture->GetConfig().height, Gamma); // Reset viewport for drawing text D3D11_VIEWPORT vp = @@ -773,33 +646,20 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, g_texture_cache->OnConfigChanged(g_ActiveConfig); VertexShaderCache::RetreiveAsyncShaders(); - SetWindowSize(fbStride, fbHeight); + SetWindowSize(xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); const bool window_resized = CheckForResize(); const bool fullscreen = D3D::GetFullscreenState(); const bool fs_changed = s_last_fullscreen_mode != fullscreen; - bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; - - if (FramebufferManagerBase::LastXfbWidth() != fbStride || - FramebufferManagerBase::LastXfbHeight() != fbHeight) - { - xfbchanged = true; - unsigned int xfb_w = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; - unsigned int xfb_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; - FramebufferManagerBase::SetLastXfbWidth(xfb_w); - FramebufferManagerBase::SetLastXfbHeight(xfb_h); - } - // Flip/present backbuffer to frontbuffer here D3D::Present(); // Resize the back buffers NOW to avoid flickering - if (CalculateTargetSize() || xfbchanged || window_resized || fs_changed || + if (CalculateTargetSize() || window_resized || fs_changed || s_last_multisamples != g_ActiveConfig.iMultisamples || s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) { - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; s_last_multisamples = g_ActiveConfig.iMultisamples; s_last_fullscreen_mode = fullscreen; PixelShaderCache::InvalidateMSAAShaders(); diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index a33eba7cd2..b35e0f9d20 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -46,8 +46,7 @@ public: TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, - u64 ticks, float Gamma) override; + void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override; void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; diff --git a/Source/Core/VideoBackends/D3D/Television.cpp b/Source/Core/VideoBackends/D3D/Television.cpp deleted file mode 100644 index 79f556cd09..0000000000 --- a/Source/Core/VideoBackends/D3D/Television.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2011 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "VideoBackends/D3D/Television.h" - -#include - -#include "Core/HW/Memmap.h" -#include "VideoBackends/D3D/D3DBase.h" -#include "VideoBackends/D3D/D3DShader.h" -#include "VideoBackends/D3D/D3DState.h" -#include "VideoBackends/D3D/D3DUtil.h" -#include "VideoBackends/D3D/VertexShaderCache.h" -#include "VideoCommon/VideoCommon.h" -#include "VideoCommon/VideoConfig.h" - -namespace DX11 -{ -static const char YUYV_DECODER_PS[] = - "// dolphin-emu YUYV decoder pixel shader\n" - - "Texture2D Tex0 : register(t0);\n" - "sampler Samp0 : register(s0);\n" - - "static const float3x3 YCBCR_TO_RGB = float3x3(\n" - "1.164, 0.000, 1.596,\n" - "1.164, -0.392, -0.813,\n" - "1.164, 2.017, 0.000\n" - ");\n" - - "void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : " - "TEXCOORD0)\n" - "{\n" - "float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n" - - // GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color - // primaries, compressed to the range Y in 16..235, U and V in 16..240. - // We want to convert it to RGB format with sRGB color primaries, with - // range 0..255. - - // Recover RGB components - "float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n" - "float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n" - - // If we were really obsessed with accuracy, we would correct for the - // differing color primaries between BT.601 and sRGB. However, this may not - // be worth the trouble because: - // - BT.601 defines two sets of primaries: one for NTSC and one for PAL. - // - sRGB's color primaries are actually an intermediate between BT.601's - // NTSC and PAL primaries. - // - If users even noticed any difference at all, they would be confused by - // the slightly-different colors in the NTSC and PAL versions of the same - // game. - // - Even the game designers probably don't pay close attention to this - // stuff. - // Still, instructions on how to do it can be found at - // - - "ocol0 = float4(rgb_601, 1);\n" - "}\n"; - -Television::Television() : m_yuyvTexture(nullptr), m_yuyvTextureSRV(nullptr), m_pShader(nullptr) -{ -} - -void Television::Init() -{ - HRESULT hr; - - // Create YUYV texture for real XFB mode - - // Initialize the texture with YCbCr black - // - // Some games use narrower XFB widths (Nintendo titles are fond of 608), - // so the sampler's BorderColor won't cover the right side - // (see sampler state below) - const unsigned int MAX_XFB_SIZE = 2 * (MAX_XFB_WIDTH)*MAX_XFB_HEIGHT; - std::vector fill(MAX_XFB_SIZE); - for (size_t i = 0; i < MAX_XFB_SIZE / sizeof(u32); ++i) - reinterpret_cast(fill.data())[i] = 0x80108010; - D3D11_SUBRESOURCE_DATA srd = {fill.data(), 2 * (MAX_XFB_WIDTH), 0}; - - // This texture format is designed for YUYV data. - D3D11_TEXTURE2D_DESC t2dd = - CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1); - hr = D3D::device->CreateTexture2D(&t2dd, &srd, &m_yuyvTexture); - CHECK(SUCCEEDED(hr), "create tv yuyv texture"); - D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture"); - - // Create shader resource view for YUYV texture - - D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC( - m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_G8R8_G8B8_UNORM); - hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV); - CHECK(SUCCEEDED(hr), "create tv yuyv texture srv"); - D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv"); - - // Create YUYV-decoding pixel shader - - m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS); - CHECK(m_pShader != nullptr, "compile and create yuyv decoder pixel shader"); - D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader"); - - // Create sampler state and set border color - // - // The default sampler border color of { 0.f, 0.f, 0.f, 0.f } - // creates a green border around the image - see issue 6483 - // (remember, the XFB is being interpreted as YUYV, and 0,0,0,0 - // is actually two green pixels in YUYV - black should be 16,128,16,128, - // but we reverse the order to match DXGI_FORMAT_G8R8_G8B8_UNORM's ordering) - float border[4] = {128.0f / 255.0f, 16.0f / 255.0f, 128.0f / 255.0f, 16.0f / 255.0f}; - D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC( - D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, - D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f); - hr = D3D::device->CreateSamplerState(&samDesc, &m_samplerState); - CHECK(SUCCEEDED(hr), "create yuyv decoder sampler state"); - D3D::SetDebugObjectName(m_samplerState, "yuyv decoder sampler state"); -} - -void Television::Shutdown() -{ - SAFE_RELEASE(m_pShader); - SAFE_RELEASE(m_yuyvTextureSRV); - SAFE_RELEASE(m_yuyvTexture); - SAFE_RELEASE(m_samplerState); -} - -void Television::Submit(u32 xfbAddr, u32 stride, u32 width, u32 height) -{ - m_curAddr = xfbAddr; - m_curWidth = width; - m_curHeight = height; - - // Load data from GameCube RAM to YUYV texture - u8* yuyvSrc = Memory::GetPointer(xfbAddr); - D3D11_BOX box = CD3D11_BOX(0, 0, 0, stride, height, 1); - D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2 * stride, 2 * stride * height); -} - -void Television::Render() -{ - if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB) - { - // Use real XFB mode - // TODO: If this is the lower field, render at a vertical offset of 1 - // line down. We could even consider implementing a deinterlacing - // algorithm. - - D3D11_RECT sourceRc = CD3D11_RECT(0, 0, int(m_curWidth), int(m_curHeight)); - - D3D::stateman->SetSampler(0, m_samplerState); - - D3D::drawShadedTexQuad(m_yuyvTextureSRV, &sourceRc, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, m_pShader, - VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout()); - } - else if (g_ActiveConfig.bUseXFB) - { - // Use virtual XFB mode - - // TODO: Eventually, Television should render the Virtual XFB mode - // display as well. - } -} -} diff --git a/Source/Core/VideoBackends/D3D/Television.h b/Source/Core/VideoBackends/D3D/Television.h deleted file mode 100644 index 2ad29cdf10..0000000000 --- a/Source/Core/VideoBackends/D3D/Television.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2011 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include "Common/CommonTypes.h" - -struct ID3D11Texture2D; -struct ID3D11ShaderResourceView; -struct ID3D11PixelShader; -struct ID3D11SamplerState; - -namespace DX11 -{ -class Television -{ -public: - Television(); - - void Init(); - void Shutdown(); - - // Submit video data to be drawn. This will change the current state of the - // TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB - // may be virtualized when rendering so the RAM may not actually be read. - void Submit(u32 xfbAddr, u32 stride, u32 width, u32 height); - - // Render the current state of the TV. - void Render(); - -private: - // Properties of last Submit call - u32 m_curAddr; - u32 m_curWidth; - u32 m_curHeight; - - // Used for real XFB mode - - ID3D11Texture2D* m_yuyvTexture; - ID3D11ShaderResourceView* m_yuyvTextureSRV; - ID3D11PixelShader* m_pShader; - ID3D11SamplerState* m_samplerState; -}; -} diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp deleted file mode 100644 index 696c5c35e0..0000000000 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright 2011 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "VideoBackends/D3D/XFBEncoder.h" -#include "Common/CommonTypes.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" -#include "VideoBackends/D3D/D3DBase.h" -#include "VideoBackends/D3D/D3DBlob.h" -#include "VideoBackends/D3D/D3DShader.h" -#include "VideoBackends/D3D/D3DState.h" -#include "VideoBackends/D3D/FramebufferManager.h" -#include "VideoBackends/D3D/Render.h" - -namespace DX11 -{ -union XFBEncodeParams -{ - struct - { - FLOAT Width; // Width and height of encoded XFB in luma pixels - FLOAT Height; - FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture - FLOAT TexTop; - FLOAT TexRight; - FLOAT TexBottom; - FLOAT Gamma; - }; - // Constant buffers must be a multiple of 16 bytes in size - u8 pad[32]; // Pad to the next multiple of 16 -}; - -static const char XFB_ENCODE_VS[] = - "// dolphin-emu XFB encoder vertex shader\n" - - "cbuffer cbParams : register(b0)\n" - "{\n" - "struct\n" // Should match XFBEncodeParams above - "{\n" - "float Width;\n" - "float Height;\n" - "float TexLeft;\n" - "float TexTop;\n" - "float TexRight;\n" - "float TexBottom;\n" - "float Gamma;\n" - "} Params;\n" - "}\n" - - "struct Output\n" - "{\n" - "float4 Pos : SV_Position;\n" - "float2 Coord : ENCODECOORD;\n" - "};\n" - - "Output main(in float2 Pos : POSITION)\n" - "{\n" - "Output result;\n" - "result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n" - "result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n" - "return result;\n" - "}\n"; - -static const char XFB_ENCODE_PS[] = - "// dolphin-emu XFB encoder pixel shader\n" - - "cbuffer cbParams : register(b0)\n" - "{\n" - "struct\n" // Should match XFBEncodeParams above - "{\n" - "float Width;\n" - "float Height;\n" - "float TexLeft;\n" - "float TexTop;\n" - "float TexRight;\n" - "float TexBottom;\n" - "float Gamma;\n" - "} Params;\n" - "}\n" - - "Texture2DArray EFBTexture : register(t0);\n" - "sampler EFBSampler : register(s0);\n" - - // GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see - // - "static const float3x4 RGB_TO_YCBCR = float3x4(\n" - "0.257, 0.504, 0.098, 16.0/255.0,\n" - "-0.148, -0.291, 0.439, 128.0/255.0,\n" - "0.439, -0.368, -0.071, 128.0/255.0\n" - ");\n" - - "float3 SampleEFB(float2 coord)\n" - "{\n" - "float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), " - "float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n" - "return EFBTexture.Sample(EFBSampler, float3(texCoord, 0.0)).rgb;\n" - "}\n" - - "void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : " - "ENCODECOORD)\n" - "{\n" - // Multiplying X by 2, moves pixel centers from (x+0.5) to (2x+1) instead of (2x+0.5), so - // subtract 0.5 to compensate - "float2 baseCoord = Coord * float2(2,1) - float2(0.5,0);\n" - // FIXME: Shall we apply gamma here, or apply it below to the Y components? - // Be careful if you apply it to Y! The Y components are in the range (16..235) / 255. - "float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left - "float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle - "float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right - - "float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n" - "float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n" - "float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n" - - // The Y components correspond to two EFB pixels, while the U and V are - // made from a blend of three EFB pixels. - "float y0 = yuvM.r;\n" - "float y1 = yuvR.r;\n" - "float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n" - "float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n" - - "ocol0 = float4(y0, u0, y1, v0);\n" - "}\n"; - -static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = { - {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}}; - -static const struct QuadVertex -{ - float posX; - float posY; -} QUAD_VERTS[4] = {{0, 0}, {1, 0}, {0, 1}, {1, 1}}; - -XFBEncoder::XFBEncoder() - : m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr), m_encodeParams(nullptr), - m_quad(nullptr), m_vShader(nullptr), m_quadLayout(nullptr), m_pShader(nullptr), - m_xfbEncodeBlendState(nullptr), m_xfbEncodeDepthState(nullptr), m_xfbEncodeRastState(nullptr), - m_efbSampler(nullptr) -{ -} - -void XFBEncoder::Init() -{ - HRESULT hr; - - // Create output texture - - // The pixel shader can generate one YUYV entry per pixel. One YUYV entry - // is created for every two EFB pixels. - D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH / 2, - MAX_XFB_HEIGHT, 1, 1, D3D11_BIND_RENDER_TARGET); - hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out); - CHECK(SUCCEEDED(hr), "create xfb encoder output texture"); - D3D::SetDebugObjectName(m_out, "xfb encoder output texture"); - - // Create output render target view - - D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC( - m_out, D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM); - hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV); - CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv"); - D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv"); - - // Create output staging buffer - - t2dd.Usage = D3D11_USAGE_STAGING; - t2dd.BindFlags = 0; - t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage); - CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer"); - D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer"); - - // Create constant buffer for uploading params to shaders - - D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER); - hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams); - CHECK(SUCCEEDED(hr), "create xfb encode params buffer"); - D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer"); - - // Create vertex quad - - bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE); - D3D11_SUBRESOURCE_DATA srd = {QUAD_VERTS, 0, 0}; - - hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad); - CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer"); - D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer"); - - // Create vertex shader - - D3DBlob* bytecode = nullptr; - if (!D3D::CompileVertexShader(XFB_ENCODE_VS, &bytecode)) - { - ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile"); - return; - } - - hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), nullptr, &m_vShader); - CHECK(SUCCEEDED(hr), "create xfb encode vertex shader"); - D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader"); - - // Create input layout for vertex quad using bytecode from vertex shader - - hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC, - sizeof(QUAD_LAYOUT_DESC) / sizeof(D3D11_INPUT_ELEMENT_DESC), - bytecode->Data(), bytecode->Size(), &m_quadLayout); - CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout"); - D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout"); - - bytecode->Release(); - - // Create pixel shader - - m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS); - if (!m_pShader) - { - ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile"); - return; - } - D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader"); - - // Create blend state - - D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); - hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState); - CHECK(SUCCEEDED(hr), "create xfb encode blend state"); - D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state"); - - // Create depth state - - D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); - dsd.DepthEnable = FALSE; - hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState); - CHECK(SUCCEEDED(hr), "create xfb encode depth state"); - D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state"); - - // Create rasterizer state - - D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT()); - rd.CullMode = D3D11_CULL_NONE; - rd.DepthClipEnable = FALSE; - hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState); - CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state"); - D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state"); - - // Create EFB texture sampler - - D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); - sd.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler); - CHECK(SUCCEEDED(hr), "create xfb encode texture sampler"); - D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler"); -} - -void XFBEncoder::Shutdown() -{ - SAFE_RELEASE(m_efbSampler); - SAFE_RELEASE(m_xfbEncodeRastState); - SAFE_RELEASE(m_xfbEncodeDepthState); - SAFE_RELEASE(m_xfbEncodeBlendState); - SAFE_RELEASE(m_pShader); - SAFE_RELEASE(m_quadLayout); - SAFE_RELEASE(m_vShader); - SAFE_RELEASE(m_quad); - SAFE_RELEASE(m_encodeParams); - SAFE_RELEASE(m_outStage); - SAFE_RELEASE(m_outRTV); - SAFE_RELEASE(m_out); -} - -void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma) -{ - HRESULT hr; - - // Reset API - - g_renderer->ResetAPIState(); - - // Set up all the state for XFB encoding - - D3D::stateman->SetPixelShader(m_pShader); - D3D::stateman->SetVertexShader(m_vShader); - D3D::stateman->SetGeometryShader(nullptr); - - D3D::stateman->PushBlendState(m_xfbEncodeBlendState); - D3D::stateman->PushDepthState(m_xfbEncodeDepthState); - D3D::stateman->PushRasterizerState(m_xfbEncodeRastState); - - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width / 2), FLOAT(height)); - D3D::context->RSSetViewports(1, &vp); - - D3D::stateman->SetInputLayout(m_quadLayout); - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - UINT stride = sizeof(QuadVertex); - UINT offset = 0; - D3D::stateman->SetVertexBuffer(m_quad, stride, offset); - - TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect); - - XFBEncodeParams params = {0}; - params.Width = FLOAT(width); - params.Height = FLOAT(height); - params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetTargetWidth(); - params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight(); - params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth(); - params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight(); - params.Gamma = gamma; - D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); - - D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); - - ID3D11ShaderResourceView* pEFB = FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); - - D3D::stateman->SetVertexConstants(m_encodeParams); - D3D::stateman->SetPixelConstants(m_encodeParams); - D3D::stateman->SetTexture(0, pEFB); - D3D::stateman->SetSampler(0, m_efbSampler); - - // Encode! - - D3D::stateman->Apply(); - D3D::context->Draw(4, 0); - - // Copy to staging buffer - - D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width / 2, height, 1); - D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); - - // Clean up state - - D3D::context->OMSetRenderTargets(0, nullptr, nullptr); - - D3D::stateman->SetSampler(0, nullptr); - D3D::stateman->SetTexture(0, nullptr); - D3D::stateman->SetPixelConstants(nullptr); - D3D::stateman->SetVertexConstants(nullptr); - - D3D::stateman->SetPixelShader(nullptr); - D3D::stateman->SetVertexShader(nullptr); - - D3D::stateman->PopRasterizerState(); - D3D::stateman->PopDepthState(); - D3D::stateman->PopBlendState(); - - // Transfer staging buffer to GameCube/Wii RAM - - D3D11_MAPPED_SUBRESOURCE map = {0}; - hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map); - CHECK(SUCCEEDED(hr), "map staging buffer"); - - u8* src = (u8*)map.pData; - for (unsigned int y = 0; y < height; ++y) - { - memcpy(dst, src, 2 * width); - dst += bpmem.copyMipMapStrideChannels * 32; - src += map.RowPitch; - } - - D3D::context->Unmap(m_outStage, 0); - - // Restore API - g_renderer->RestoreAPIState(); - D3D::stateman->Apply(); // force unbind efb texture as shader resource - FramebufferManager::BindEFBRenderTarget(); -} -} diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.h b/Source/Core/VideoBackends/D3D/XFBEncoder.h deleted file mode 100644 index 91da877b8b..0000000000 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2011 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include "VideoCommon/VideoCommon.h" - -struct ID3D11Texture2D; -struct ID3D11RenderTargetView; -struct ID3D11Buffer; -struct ID3D11VertexShader; -struct ID3D11PixelShader; -struct ID3D11InputLayout; -struct ID3D11BlendState; -struct ID3D11DepthStencilState; -struct ID3D11RasterizerState; -struct ID3D11SamplerState; - -namespace DX11 -{ -class XFBEncoder -{ -public: - XFBEncoder(); - - void Init(); - void Shutdown(); - - void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma); - -private: - ID3D11Texture2D* m_out; - ID3D11RenderTargetView* m_outRTV; - ID3D11Texture2D* m_outStage; - ID3D11Buffer* m_encodeParams; - ID3D11Buffer* m_quad; - ID3D11VertexShader* m_vShader; - ID3D11InputLayout* m_quadLayout; - ID3D11PixelShader* m_pShader; - ID3D11BlendState* m_xfbEncodeBlendState; - ID3D11DepthStencilState* m_xfbEncodeDepthState; - ID3D11RasterizerState* m_xfbEncodeRastState; - ID3D11SamplerState* m_efbSampler; -}; -} diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index ced41e2b13..9597ac7d04 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -78,6 +78,8 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsInternalResolutionFrameDumps = false; g_Config.backend_info.bSupportsGPUTextureDecoding = false; g_Config.backend_info.bSupportsST3CTextures = false; + g_Config.backend_info.bSupportsCopyToVram = true; + g_Config.backend_info.bForceCopyToRam = false; g_Config.backend_info.bSupportsBitfield = false; g_Config.backend_info.bSupportsDynamicSamplerIndexing = false; g_Config.backend_info.bSupportsBPTCTextures = false; diff --git a/Source/Core/VideoBackends/Null/FramebufferManager.h b/Source/Core/VideoBackends/Null/FramebufferManager.h deleted file mode 100644 index d68a4a7d1f..0000000000 --- a/Source/Core/VideoBackends/Null/FramebufferManager.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "Common/CommonTypes.h" -#include "VideoCommon/FramebufferManagerBase.h" - -class XFBSource : public XFBSourceBase -{ -public: - void DecodeToTexture(u32 xfb_addr, u32 fb_width, u32 fb_height) override {} - void CopyEFB(float gamma) override {} -}; - -class FramebufferManager : public FramebufferManagerBase -{ -public: - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override - { - return std::make_unique(); - } - - std::pair GetTargetSize() const override { return std::make_pair(0, 0); } - void CopyToRealXFB(u32 xfb_addr, u32 fb_stride, u32 fb_height, const EFBRectangle& source_rc, - float gamma = 1.0f) override - { - } -}; diff --git a/Source/Core/VideoBackends/Null/Null.vcxproj b/Source/Core/VideoBackends/Null/Null.vcxproj index 178575ef81..664488035e 100644 --- a/Source/Core/VideoBackends/Null/Null.vcxproj +++ b/Source/Core/VideoBackends/Null/Null.vcxproj @@ -43,7 +43,6 @@ - diff --git a/Source/Core/VideoBackends/Null/NullBackend.cpp b/Source/Core/VideoBackends/Null/NullBackend.cpp index 2a52fe7172..1bb8d6248e 100644 --- a/Source/Core/VideoBackends/Null/NullBackend.cpp +++ b/Source/Core/VideoBackends/Null/NullBackend.cpp @@ -7,7 +7,6 @@ // This backend tries not to do anything in the backend, // but everything in VideoCommon. -#include "VideoBackends/Null/FramebufferManager.h" #include "VideoBackends/Null/PerfQuery.h" #include "VideoBackends/Null/Render.h" #include "VideoBackends/Null/ShaderCache.h" @@ -15,6 +14,7 @@ #include "VideoBackends/Null/VertexManager.h" #include "VideoBackends/Null/VideoBackend.h" +#include "VideoCommon/FramebufferManagerBase.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" @@ -68,7 +68,7 @@ void VideoBackend::Video_Prepare() g_renderer = std::make_unique(); g_vertex_manager = std::make_unique(); g_perf_query = std::make_unique(); - g_framebuffer_manager = std::make_unique(); + g_framebuffer_manager = std::make_unique(); g_texture_cache = std::make_unique(); VertexShaderCache::s_instance = std::make_unique(); GeometryShaderCache::s_instance = std::make_unique(); diff --git a/Source/Core/VideoBackends/Null/Render.cpp b/Source/Core/VideoBackends/Null/Render.cpp index 084a7b49af..b1a88f7a80 100644 --- a/Source/Core/VideoBackends/Null/Render.cpp +++ b/Source/Core/VideoBackends/Null/Render.cpp @@ -36,7 +36,7 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) return result; } -void Renderer::SwapImpl(u32, u32, u32, u32, const EFBRectangle&, u64, float) +void Renderer::SwapImpl(AbstractTexture*, const EFBRectangle&, u64, float) { UpdateActiveConfig(); } diff --git a/Source/Core/VideoBackends/Null/Render.h b/Source/Core/VideoBackends/Null/Render.h index 2187f147c0..2a21918f81 100644 --- a/Source/Core/VideoBackends/Null/Render.h +++ b/Source/Core/VideoBackends/Null/Render.h @@ -21,8 +21,7 @@ public: void BBoxWrite(int index, u16 value) override {} TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, const EFBRectangle& rc, - u64 ticks, float gamma) override; + void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override; void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp index 91be73a9f3..a670a47111 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp @@ -33,7 +33,6 @@ bool FramebufferManager::m_enable_stencil_buffer; GLenum FramebufferManager::m_textureType; std::vector FramebufferManager::m_efbFramebuffer; -GLuint FramebufferManager::m_xfbFramebuffer; GLuint FramebufferManager::m_efbColor; GLuint FramebufferManager::m_efbDepth; GLuint FramebufferManager::m_efbColorSwap; // for hot swap when reinterpreting EFB pixel formats @@ -110,7 +109,6 @@ bool FramebufferManager::HasStencilBuffer() FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, bool enable_stencil_buffer) { - m_xfbFramebuffer = 0; m_efbColor = 0; m_efbDepth = 0; m_efbColorSwap = 0; @@ -189,9 +187,6 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms CreateTexture(m_textureType, depth_internal_format, depth_pixel_format, depth_data_type); m_efbColorSwap = CreateTexture(m_textureType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); - // Create XFB framebuffer; targets will be created elsewhere. - glGenFramebuffers(1, &m_xfbFramebuffer); - // Bind target textures to EFB framebuffer. glGenFramebuffers(m_EFBLayers, m_efbFramebuffer.data()); BindLayeredTexture(m_efbColor, m_efbFramebuffer, GL_COLOR_ATTACHMENT0, m_textureType); @@ -419,9 +414,6 @@ FramebufferManager::~FramebufferManager() m_efbFramebuffer.clear(); m_resolvedFramebuffer.clear(); - glDeleteFramebuffers(1, &m_xfbFramebuffer); - m_xfbFramebuffer = 0; - glObj[0] = m_resolvedColorTexture; glObj[1] = m_resolvedDepthTexture; glDeleteTextures(2, glObj); @@ -527,21 +519,6 @@ void FramebufferManager::ResolveEFBStencilTexture() glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); } -void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, - const EFBRectangle& sourceRc, float Gamma) -{ - u8* xfb_in_ram = Memory::GetPointer(xfbAddr); - if (!xfb_in_ram) - { - WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); - return; - } - - TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc); - TextureConverter::EncodeToRamYUYV(ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, - sourceRc.GetWidth(), fbStride, fbHeight); -} - GLuint FramebufferManager::GetResolvedFramebuffer() { if (m_msaaSamples <= 1) @@ -610,61 +587,6 @@ void FramebufferManager::ReinterpretPixelData(unsigned int convtype) g_renderer->RestoreAPIState(); } -XFBSource::~XFBSource() -{ - glDeleteTextures(1, &texture); -} - -void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) -{ - TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, texture); -} - -void XFBSource::CopyEFB(float Gamma) -{ - g_renderer->ResetAPIState(); - - // Copy EFB data to XFB and restore render target again - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer()); - - for (int i = 0; i < m_layers; i++) - { - // Bind EFB and texture layer - glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer(i)); - glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, i); - - glBlitFramebuffer(0, 0, texWidth, texHeight, 0, 0, texWidth, texHeight, GL_COLOR_BUFFER_BIT, - GL_NEAREST); - } - - // Return to EFB. - FramebufferManager::SetFramebuffer(0); - - g_renderer->RestoreAPIState(); -} - -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) -{ - GLuint texture; - - glGenTextures(1, &texture); - - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, texture); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, target_width, target_height, layers, 0, GL_RGBA, - GL_UNSIGNED_BYTE, nullptr); - - return std::make_unique(texture, layers); -} - -std::pair FramebufferManager::GetTargetSize() const -{ - return std::make_pair(m_targetWidth, m_targetHeight); -} - void FramebufferManager::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) { g_renderer->ResetAPIState(); diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.h b/Source/Core/VideoBackends/OGL/FramebufferManager.h index 62b2f5ce3c..f68556bf90 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.h +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.h @@ -48,18 +48,6 @@ namespace OGL { -struct XFBSource : public XFBSourceBase -{ - XFBSource(GLuint tex, int layers) : texture(tex), m_layers(layers) {} - ~XFBSource(); - - void CopyEFB(float Gamma) override; - void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override; - - const GLuint texture; - const int m_layers; -}; - class FramebufferManager : public FramebufferManagerBase { public: @@ -77,7 +65,6 @@ public: { return (layer < m_EFBLayers) ? m_efbFramebuffer[layer] : m_efbFramebuffer.back(); } - static GLuint GetXFBFramebuffer() { return m_xfbFramebuffer; } // Resolved framebuffer is only used in MSAA mode. static GLuint GetResolvedFramebuffer(); static void SetFramebuffer(GLuint fb); @@ -109,13 +96,6 @@ private: GLenum data_type); void BindLayeredTexture(GLuint texture, const std::vector& framebuffers, GLenum attachment, GLenum texture_type); - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override; - std::pair GetTargetSize() const override; - - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma) override; static int m_targetWidth; static int m_targetHeight; @@ -123,7 +103,6 @@ private: static GLenum m_textureType; static std::vector m_efbFramebuffer; - static GLuint m_xfbFramebuffer; static GLuint m_efbColor; static GLuint m_efbDepth; static GLuint diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.cpp b/Source/Core/VideoBackends/OGL/OGLTexture.cpp index 8569e9b8b0..659cc9764b 100644 --- a/Source/Core/VideoBackends/OGL/OGLTexture.cpp +++ b/Source/Core/VideoBackends/OGL/OGLTexture.cpp @@ -66,22 +66,6 @@ GLenum GetGLTypeForTextureFormat(AbstractTextureFormat format) } } // Anonymous namespace -bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width, - int virtual_height, unsigned int level) -{ - if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL) - return false; - int width = std::max(virtual_width >> level, 1); - int height = std::max(virtual_height >> level, 1); - std::vector data(width * height * 4); - glActiveTexture(GL_TEXTURE9); - glBindTexture(textarget, tex); - glGetTexImage(textarget, level, GL_RGBA, GL_UNSIGNED_BYTE, data.data()); - OGLTexture::SetStage(); - - return TextureToPng(data.data(), width * 4, filename, width, height, true); -} - OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config) { glGenTextures(1, &m_texId); @@ -164,15 +148,73 @@ void OGLTexture::Bind(unsigned int stage) } } -bool OGLTexture::Save(const std::string& filename, unsigned int level) +std::optional OGLTexture::MapFullImpl() { - // We can't dump compressed textures currently (it would mean drawing them to a RGBA8 - // framebuffer, and saving that). TextureCache does not call Save for custom textures - // anyway, so this is fine for now. - _assert_(m_config.format == AbstractTextureFormat::RGBA8); + if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL) + return {}; - return SaveTexture(filename, GL_TEXTURE_2D_ARRAY, m_texId, m_config.width, m_config.height, - level); + m_staging_data.reserve(m_config.width * m_config.height * 4); + glActiveTexture(GL_TEXTURE9); + + glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId); + glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_staging_data.data()); + OGLTexture::SetStage(); + return AbstractTexture::RawTextureInfo{reinterpret_cast(m_staging_data.data()), + m_config.width * 4, m_config.width, m_config.height}; +} + +std::optional OGLTexture::MapRegionImpl(u32 level, u32 x, u32 y, + u32 width, u32 height) +{ + if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL) + return {}; + m_staging_data.reserve(m_config.width * m_config.height * 4); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId); + if (g_ogl_config.bSupportTextureSubImage) + { + glGetTextureSubImage(GL_TEXTURE_2D_ARRAY, level, GLint(x), GLint(y), 0, GLsizei(width), + GLsizei(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, GLsizei(width * height * 4), + m_staging_data.data()); + } + else + { + MapRegionSlow(level, x, y, width, height); + } + OGLTexture::SetStage(); + return AbstractTexture::RawTextureInfo{m_staging_data.data(), width * 4, width, height}; +} + +void OGLTexture::MapRegionSlow(u32 level, u32 x, u32 y, u32 width, u32 height) +{ + glActiveTexture(GL_TEXTURE9); + + glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId); + glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_staging_data.data()); + + // Now copy the region out of the staging data + + const u32 partial_stride = width * 4; + + std::vector partial_data; + partial_data.resize(partial_stride * height); + + const u32 staging_stride = m_config.width * 4; + const u32 x_offset = x * 4; + + auto staging_location = m_staging_data.begin() + staging_stride * y; + auto partial_location = partial_data.begin(); + + for (size_t i = 0; i < height; ++i) + { + auto starting_location = staging_location + x_offset; + std::copy(starting_location, starting_location + partial_stride, partial_location); + staging_location += staging_stride; + partial_location += partial_stride; + } + + // Now swap the region back in for the staging data + m_staging_data.swap(partial_data); } void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* source, diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.h b/Source/Core/VideoBackends/OGL/OGLTexture.h index 029afe272f..91cb09bbca 100644 --- a/Source/Core/VideoBackends/OGL/OGLTexture.h +++ b/Source/Core/VideoBackends/OGL/OGLTexture.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "Common/GL/GLUtil.h" #include "VideoCommon/AbstractTexture.h" @@ -17,7 +19,6 @@ public: ~OGLTexture(); void Bind(unsigned int stage) override; - bool Save(const std::string& filename, unsigned int level) override; void CopyRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, @@ -32,8 +33,14 @@ public: static void SetStage(); private: + std::optional MapFullImpl() override; + std::optional MapRegionImpl(u32 level, u32 x, u32 y, u32 width, + u32 height) override; + void MapRegionSlow(u32 level, u32 x, u32 y, u32 width, u32 height); + GLuint m_texId; GLuint m_framebuffer = 0; + std::vector m_staging_data; }; } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.cpp b/Source/Core/VideoBackends/OGL/PostProcessing.cpp index f400bc56ef..bf34e2a54c 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.cpp +++ b/Source/Core/VideoBackends/OGL/PostProcessing.cpp @@ -25,7 +25,7 @@ static const char s_vertex_shader[] = "out vec2 uv0;\n" "void main(void) {\n" " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - " uv0 = rawpos * src_rect.zw + src_rect.xy;\n" + " uv0 = vec2(mix(src_rect.xy, src_rect.zw, rawpos));\n" "}\n"; OpenGLPostProcessing::OpenGLPostProcessing() : m_initialized(false) @@ -52,8 +52,8 @@ void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle glUniform4f(m_uniform_resolution, (float)src_width, (float)src_height, 1.0f / (float)src_width, 1.0f / (float)src_height); - glUniform4f(m_uniform_src_rect, src.left / (float)src_width, src.bottom / (float)src_height, - src.GetWidth() / (float)src_width, src.GetHeight() / (float)src_height); + glUniform4f(m_uniform_src_rect, src.left / (float)src_width, src.top / (float)src_height, + src.right / (float)src_width, src.bottom / (float)src_height); glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed()); glUniform1i(m_uniform_layer, layer); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index ccf89b45f2..2125102fe0 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -66,7 +66,6 @@ static std::unique_ptr s_raster_font; static int s_MSAASamples = 1; static u32 s_last_multisamples = 1; static bool s_last_stereo_mode = false; -static bool s_last_xfb_mode = false; static bool s_vsync; @@ -461,6 +460,7 @@ Renderer::Renderer() GLExtensions::Supports("GL_EXT_copy_image") || GLExtensions::Supports("GL_OES_copy_image")) && !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_COPYIMAGE); + g_ogl_config.bSupportTextureSubImage = GLExtensions::Supports("ARB_get_texture_sub_image"); // Desktop OpenGL supports the binding layout if it supports 420pack // OpenGL ES 3.1 supports it implicitly without an extension @@ -726,7 +726,6 @@ Renderer::Renderer() s_MSAASamples = s_last_multisamples; s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; // Handle VSync on/off s_vsync = g_ActiveConfig.IsVSync(); @@ -791,12 +790,7 @@ Renderer::Renderer() ClearEFBCache(); } -Renderer::~Renderer() -{ - FlushFrameDump(); - FinishFrameData(); - DestroyFrameDumpResources(); -} +Renderer::~Renderer() = default; void Renderer::Shutdown() { @@ -1331,8 +1325,8 @@ void Renderer::SetBlendingState(const BlendingState& state) } // This function has the final picture. We adjust the aspect ratio here. -void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, - const EFBRectangle& rc, u64 ticks, float Gamma) +void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks, + float Gamma) { if (g_ogl_config.bSupportsDebug) { @@ -1342,20 +1336,11 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, glDisable(GL_DEBUG_OUTPUT); } - if ((!m_xfb_written && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) - { - Core::Callback_VideoCopiedToXFB(false); - return; - } + auto* xfb_texture = static_cast(texture); - u32 xfbCount = 0; - const XFBSourceBase* const* xfbSourceList = - FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); - if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0)) - { - Core::Callback_VideoCopiedToXFB(false); - return; - } + TargetRectangle sourceRc = xfb_region; + sourceRc.top = xfb_region.GetHeight(); + sourceRc.bottom = 0; ResetAPIState(); @@ -1366,49 +1351,16 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, std::swap(flipped_trc.top, flipped_trc.bottom); // Copy the framebuffer to screen. - DrawFrame(0, flipped_trc, rc, xfbAddr, xfbSourceList, xfbCount, fbWidth, fbStride, fbHeight); - - // The FlushFrameDump call here is necessary even after frame dumping is stopped. - // If left out, screenshots are "one frame" behind, as an extra frame is dumped and buffered. - FlushFrameDump(); - if (IsFrameDumping()) - { - // Currently, we only use the off-screen buffer as a frame dump source if full-resolution - // frame dumping is enabled, saving the need for an extra copy. In the future, this could - // be extended to be used for surfaceless contexts as well. - bool use_offscreen_buffer = g_ActiveConfig.bInternalResolutionFrameDumps; - if (use_offscreen_buffer) - { - // DumpFrameUsingFBO resets GL_FRAMEBUFFER, so change back to the window for drawing OSD. - DumpFrameUsingFBO(rc, xfbAddr, xfbSourceList, xfbCount, fbWidth, fbStride, fbHeight, ticks); - } - else - { - // GL_READ_FRAMEBUFFER is set by GL_FRAMEBUFFER in DrawFrame -> Draw{EFB,VirtualXFB,RealXFB}. - DumpFrame(flipped_trc, ticks); - } - } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + BlitScreen(sourceRc, flipped_trc, xfb_texture->GetRawTexIdentifier(), + xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); // Finish up the current frame, print some stats - SetWindowSize(fbStride, fbHeight); + SetWindowSize(xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); GLInterface->Update(); // just updates the render window position and the backbuffer size - bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; - - if (FramebufferManagerBase::LastXfbWidth() != fbStride || - FramebufferManagerBase::LastXfbHeight() != fbHeight) - { - xfbchanged = true; - unsigned int const last_w = - (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; - unsigned int const last_h = - (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; - FramebufferManagerBase::SetLastXfbWidth(last_w); - FramebufferManagerBase::SetLastXfbHeight(last_h); - } - bool window_resized = false; int window_width = static_cast(std::max(GLInterface->GetBackBufferWidth(), 1u)); int window_height = static_cast(std::max(GLInterface->GetBackBufferHeight(), 1u)); @@ -1428,9 +1380,8 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, stencil_buffer_enabled != BoundingBox::NeedsStencilBuffer() || s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0); - if (xfbchanged || window_resized || fb_needs_update) + if (window_resized || fb_needs_update) { - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; UpdateDrawRectangle(); } if (fb_needs_update) @@ -1523,241 +1474,13 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, ClearEFBCache(); } -void Renderer::DrawFrame(GLuint framebuffer, const TargetRectangle& target_rc, - const EFBRectangle& source_rc, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height) -{ - if (g_ActiveConfig.bUseXFB) - { - if (g_ActiveConfig.bUseRealXFB) - DrawRealXFB(framebuffer, target_rc, xfb_sources, xfb_count, fb_width, fb_stride, fb_height); - else - DrawVirtualXFB(framebuffer, target_rc, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, - fb_height); - } - else - { - DrawEFB(framebuffer, target_rc, source_rc); - } -} - void Renderer::DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc, - const EFBRectangle& source_rc) + const TargetRectangle& source_rc) { - TargetRectangle scaled_source_rc = ConvertEFBRectangle(source_rc); - // for msaa mode, we must resolve the efb content to non-msaa GLuint tex = FramebufferManager::ResolveAndGetRenderTarget(source_rc); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - BlitScreen(scaled_source_rc, target_rc, tex, m_target_width, m_target_height); -} - -void Renderer::DrawVirtualXFB(GLuint framebuffer, const TargetRectangle& target_rc, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height) -{ - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - - for (u32 i = 0; i < xfb_count; ++i) - { - const XFBSource* xfbSource = static_cast(xfb_sources[i]); - - TargetRectangle draw_rc; - TargetRectangle source_rc; - source_rc.left = xfbSource->sourceRc.left; - source_rc.right = xfbSource->sourceRc.right; - source_rc.top = xfbSource->sourceRc.top; - source_rc.bottom = xfbSource->sourceRc.bottom; - - // use virtual xfb with offset - int xfbHeight = xfbSource->srcHeight; - int xfbWidth = xfbSource->srcWidth; - int hOffset = (static_cast(xfbSource->srcAddr) - static_cast(xfb_addr)) / - (static_cast(fb_stride) * 2); - - draw_rc.top = target_rc.top - hOffset * target_rc.GetHeight() / static_cast(fb_height); - draw_rc.bottom = - target_rc.top - (hOffset + xfbHeight) * target_rc.GetHeight() / static_cast(fb_height); - draw_rc.left = - target_rc.left + - (target_rc.GetWidth() - xfbWidth * target_rc.GetWidth() / static_cast(fb_stride)) / 2; - draw_rc.right = - target_rc.left + - (target_rc.GetWidth() + xfbWidth * target_rc.GetWidth() / static_cast(fb_stride)) / 2; - - // The following code disables auto stretch. Kept for reference. - // scale draw area for a 1 to 1 pixel mapping with the draw target - // float h_scale = static_cast(fb_width) / static_cast(target_rc.GetWidth()); - // float v_scale = static_cast(fb_height) / static_cast(target_rc.GetHeight()); - // draw_rc.top *= v_scale; - // draw_rc.bottom *= v_scale; - // draw_rc.left *= h_scale; - // draw_rc.right *= h_scale; - - source_rc.right -= Renderer::EFBToScaledX(fb_stride - fb_width); - - BlitScreen(source_rc, draw_rc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight); - } -} - -void Renderer::DrawRealXFB(GLuint framebuffer, const TargetRectangle& target_rc, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height) -{ - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - - for (u32 i = 0; i < xfb_count; ++i) - { - const XFBSource* xfbSource = static_cast(xfb_sources[i]); - - TargetRectangle source_rc; - source_rc.left = xfbSource->sourceRc.left; - source_rc.right = xfbSource->sourceRc.right; - source_rc.top = xfbSource->sourceRc.top; - source_rc.bottom = xfbSource->sourceRc.bottom; - - source_rc.right -= fb_stride - fb_width; - - // RealXFB doesn't call ConvertEFBRectangle for sourceRc, therefore it is still assuming a top- - // left origin. The top offset is always zero (see FramebufferManagerBase::GetRealXFBSource). - source_rc.top = source_rc.bottom; - source_rc.bottom = 0; - - TargetRectangle draw_rc = target_rc; - BlitScreen(source_rc, draw_rc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight); - } -} - -void Renderer::FlushFrameDump() -{ - if (!m_last_frame_exported) - return; - - FinishFrameData(); - glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]); - m_frame_pbo_is_mapped[0] = true; - void* data = glMapBufferRange( - GL_PIXEL_PACK_BUFFER, 0, m_last_frame_width[0] * m_last_frame_height[0] * 4, GL_MAP_READ_BIT); - DumpFrameData(reinterpret_cast(data), m_last_frame_width[0], m_last_frame_height[0], - m_last_frame_width[0] * 4, m_last_frame_state, true); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - m_last_frame_exported = false; -} - -void Renderer::DumpFrame(const TargetRectangle& flipped_trc, u64 ticks) -{ - if (!m_frame_dumping_pbo[0]) - { - glGenBuffers(2, m_frame_dumping_pbo.data()); - glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]); - } - else - { - FlushFrameDump(); - std::swap(m_frame_dumping_pbo[0], m_frame_dumping_pbo[1]); - std::swap(m_frame_pbo_is_mapped[0], m_frame_pbo_is_mapped[1]); - std::swap(m_last_frame_width[0], m_last_frame_width[1]); - std::swap(m_last_frame_height[0], m_last_frame_height[1]); - glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]); - if (m_frame_pbo_is_mapped[0]) - glUnmapBuffer(GL_PIXEL_PACK_BUFFER); - m_frame_pbo_is_mapped[0] = false; - } - - if (flipped_trc.GetWidth() != m_last_frame_width[0] || - flipped_trc.GetHeight() != m_last_frame_height[0]) - { - m_last_frame_width[0] = flipped_trc.GetWidth(); - m_last_frame_height[0] = flipped_trc.GetHeight(); - glBufferData(GL_PIXEL_PACK_BUFFER, m_last_frame_width[0] * m_last_frame_height[0] * 4, nullptr, - GL_STREAM_READ); - } - - m_last_frame_state = AVIDump::FetchState(ticks); - m_last_frame_exported = true; - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(flipped_trc.left, flipped_trc.bottom, m_last_frame_width[0], m_last_frame_height[0], - GL_RGBA, GL_UNSIGNED_BYTE, 0); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); -} - -void Renderer::DumpFrameUsingFBO(const EFBRectangle& source_rc, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, - u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks) -{ - // This needs to be converted to the GL bottom-up window coordinate system. - TargetRectangle render_rc = CalculateFrameDumpDrawRectangle(); - std::swap(render_rc.top, render_rc.bottom); - - // Ensure the render texture meets the size requirements of the draw area. - u32 render_width = static_cast(render_rc.GetWidth()); - u32 render_height = static_cast(render_rc.GetHeight()); - PrepareFrameDumpRenderTexture(render_width, render_height); - - // Ensure the alpha channel of the render texture is blank. The frame dump backend expects - // that the alpha is set to 1.0 for all pixels. - glBindFramebuffer(GL_FRAMEBUFFER, m_frame_dump_render_framebuffer); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - // Render the frame into the frame dump render texture. Disable alpha writes in case the - // post-processing shader writes a non-1.0 value. - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - DrawFrame(m_frame_dump_render_framebuffer, render_rc, source_rc, xfb_addr, xfb_sources, xfb_count, - fb_width, fb_stride, fb_height); - - // Copy frame to output buffer. This assumes that GL_FRAMEBUFFER has been set. - DumpFrame(render_rc, ticks); - - // Restore state after drawing. This isn't the game state, it's the state set by ResetAPIState. - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -void Renderer::PrepareFrameDumpRenderTexture(u32 width, u32 height) -{ - // Ensure framebuffer exists (we lazily allocate it in case frame dumping isn't used). - // Or, resize texture if it isn't large enough to accommodate the current frame. - if (m_frame_dump_render_texture != 0 && m_frame_dump_render_framebuffer != 0 && - m_frame_dump_render_texture_width >= width && m_frame_dump_render_texture_height >= height) - { - return; - } - - // Recreate texture objects. - if (m_frame_dump_render_texture != 0) - glDeleteTextures(1, &m_frame_dump_render_texture); - if (m_frame_dump_render_framebuffer != 0) - glDeleteFramebuffers(1, &m_frame_dump_render_framebuffer); - - glGenTextures(1, &m_frame_dump_render_texture); - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D, m_frame_dump_render_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - - glGenFramebuffers(1, &m_frame_dump_render_framebuffer); - FramebufferManager::SetFramebuffer(m_frame_dump_render_framebuffer); - FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - m_frame_dump_render_texture, 0); - - m_frame_dump_render_texture_width = width; - m_frame_dump_render_texture_height = height; - OGLTexture::SetStage(); -} - -void Renderer::DestroyFrameDumpResources() -{ - if (m_frame_dump_render_framebuffer) - glDeleteFramebuffers(1, &m_frame_dump_render_framebuffer); - if (m_frame_dump_render_texture) - glDeleteTextures(1, &m_frame_dump_render_texture); - if (m_frame_dumping_pbo[0]) - glDeleteBuffers(2, m_frame_dumping_pbo.data()); + BlitScreen(source_rc, target_rc, tex, m_target_width, m_target_height); } // ALWAYS call RestoreAPIState for each ResetAPIState call you're doing diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index 8efea70bec..725cc7a639 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include "Common/GL/GLUtil.h" @@ -59,6 +58,7 @@ struct VideoConfig bool bSupportsImageLoadStore; bool bSupportsAniso; bool bSupportsBitfield; + bool bSupportTextureSubImage; const char* gl_vendor; const char* gl_renderer; @@ -98,8 +98,7 @@ public: TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, - u64 ticks, float Gamma) override; + void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override; void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; @@ -112,42 +111,10 @@ private: void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const void* data); - // Draw either the EFB, or specified XFB sources to the currently-bound framebuffer. - void DrawFrame(GLuint framebuffer, const TargetRectangle& target_rc, - const EFBRectangle& source_rc, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - void DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc, const EFBRectangle& source_rc); - void DrawVirtualXFB(GLuint framebuffer, const TargetRectangle& target_rc, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - void DrawRealXFB(GLuint framebuffer, const TargetRectangle& target_rc, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); + void DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc, + const TargetRectangle& source_rc); void BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, int src_width, int src_height); - - void FlushFrameDump(); - void DumpFrame(const TargetRectangle& flipped_trc, u64 ticks); - void DumpFrameUsingFBO(const EFBRectangle& source_rc, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height, u64 ticks); - - // Frame dumping framebuffer, we render to this, then read it back - void PrepareFrameDumpRenderTexture(u32 width, u32 height); - void DestroyFrameDumpResources(); - GLuint m_frame_dump_render_texture = 0; - GLuint m_frame_dump_render_framebuffer = 0; - u32 m_frame_dump_render_texture_width = 0; - u32 m_frame_dump_render_texture_height = 0; - - // avi dumping state to delay one frame - std::array m_frame_dumping_pbo = {}; - std::array m_frame_pbo_is_mapped = {}; - std::array m_last_frame_width = {}; - std::array m_last_frame_height = {}; - bool m_last_frame_exported = false; - AVIDump::Frame m_last_frame_state; }; } diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index df4bcb7f00..aa2c60976b 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -388,9 +388,10 @@ void main() void TextureCache::CreateTextureDecodingResources() { static const GLenum gl_view_types[TextureConversionShader::BUFFER_FORMAT_COUNT] = { - GL_R8UI, // BUFFER_FORMAT_R8_UINT - GL_R16UI, // BUFFER_FORMAT_R16_UINT - GL_RG32UI, // BUFFER_FORMAT_R32G32_UINT + GL_R8UI, // BUFFER_FORMAT_R8_UINT + GL_R16UI, // BUFFER_FORMAT_R16_UINT + GL_RG32UI, // BUFFER_FORMAT_R32G32_UINT + GL_RGBA8UI, // BUFFER_FORMAT_RGBA8_UINT }; glGenTextures(TextureConversionShader::BUFFER_FORMAT_COUNT, diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/TextureConverter.cpp index 67f1bcc28e..a2460bf935 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.cpp +++ b/Source/Core/VideoBackends/OGL/TextureConverter.cpp @@ -41,101 +41,16 @@ static GLuint s_dstTexture = 0; // for encoding to RAM const int renderBufferWidth = EFB_WIDTH * 4; const int renderBufferHeight = 1024; -static SHADER s_rgbToYuyvProgram; -static int s_rgbToYuyvUniform_loc; - -static SHADER s_yuyvToRgbProgram; - struct EncodingProgram { SHADER program; GLint copy_position_uniform; + GLint y_scale_uniform; }; static std::map s_encoding_programs; static GLuint s_PBO = 0; // for readback with different strides -static void CreatePrograms() -{ - /* TODO: Accuracy Improvements - * - * This shader doesn't really match what the GameCube does internally in the - * copy pipeline. - * 1. It uses OpenGL's built in filtering when yscaling, someone could work - * out how the copypipeline does it's filtering and implement it correctly - * in this shader. - * 2. Deflickering isn't implemented, a futher filtering over 3 lines. - * Isn't really needed on non-interlaced monitors (and would lower quality; - * But hey, accuracy!) - * 3. Flipper's YUYV conversion implements a 3 pixel horizontal blur on the - * UV channels, centering the U channel on the Left pixel and the V channel - * on the Right pixel. - * The current implementation Centers both UV channels at the same place - * inbetween the two Pixels, and only blurs over these two pixels. - */ - // Output is BGRA because that is slightly faster than RGBA. - const char* VProgramRgbToYuyv = - "out vec2 uv0;\n" - "uniform vec4 copy_position;\n" // left, top, right, bottom - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - " uv0 = mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy);\n" - "}\n"; - const char* FProgramRgbToYuyv = - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "in vec2 uv0;\n" - "out vec4 ocol0;\n" - "void main()\n" - "{\n" - " vec3 c0 = texture(samp9, vec3(uv0 - dFdx(uv0) * 0.25, 0.0)).rgb;\n" - " vec3 c1 = texture(samp9, vec3(uv0 + dFdx(uv0) * 0.25, 0.0)).rgb;\n" - " vec3 c01 = (c0 + c1) * 0.5;\n" - " vec3 y_const = vec3(0.257,0.504,0.098);\n" - " vec3 u_const = vec3(-0.148,-0.291,0.439);\n" - " vec3 v_const = vec3(0.439,-0.368,-0.071);\n" - " vec4 const3 = vec4(0.0625,0.5,0.0625,0.5);\n" - " ocol0 = vec4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + " - "const3;\n" - "}\n"; - ProgramShaderCache::CompileShader(s_rgbToYuyvProgram, VProgramRgbToYuyv, FProgramRgbToYuyv); - s_rgbToYuyvUniform_loc = glGetUniformLocation(s_rgbToYuyvProgram.glprogid, "copy_position"); - - /* TODO: Accuracy Improvements - * - * The YVYU to RGB conversion here matches the RGB to YUYV done above, but - * if a game modifies or adds images to the XFB then it should be using the - * same algorithm as the flipper, and could result in slight color inaccuracies - * when run back through this shader. - */ - const char* VProgramYuyvToRgb = "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - "}\n"; - const char* FProgramYuyvToRgb = "SAMPLER_BINDING(9) uniform sampler2D samp9;\n" - "in vec2 uv0;\n" - "out vec4 ocol0;\n" - "void main()\n" - "{\n" - " ivec2 uv = ivec2(gl_FragCoord.xy);\n" - // We switch top/bottom here. TODO: move this to screen blit. - " ivec2 ts = textureSize(samp9, 0);\n" - " vec4 c0 = texelFetch(samp9, ivec2(uv.x>>1, ts.y-uv.y-1), 0);\n" - " float y = mix(c0.r, c0.b, (uv.x & 1) == 1);\n" - " float yComp = 1.164 * (y - 0.0625);\n" - " float uComp = c0.g - 0.5;\n" - " float vComp = c0.a - 0.5;\n" - " ocol0 = vec4(yComp + (1.596 * vComp),\n" - " yComp - (0.813 * vComp) - (0.391 * uComp),\n" - " yComp + (2.018 * uComp),\n" - " 1.0);\n" - "}\n"; - ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgramYuyvToRgb, FProgramYuyvToRgb); -} - static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params) { auto iter = s_encoding_programs.find(params); @@ -166,6 +81,7 @@ static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params) PanicAlert("Failed to compile texture encoding shader."); program.copy_position_uniform = glGetUniformLocation(program.program.glprogid, "position"); + program.y_scale_uniform = glGetUniformLocation(program.program.glprogid, "y_scale"); return s_encoding_programs.emplace(params, program).first->second; } @@ -189,8 +105,6 @@ void Init() FramebufferManager::SetFramebuffer(0); glGenBuffers(1, &s_PBO); - - CreatePrograms(); } void Shutdown() @@ -200,9 +114,6 @@ void Shutdown() glDeleteBuffers(1, &s_PBO); glDeleteFramebuffers(2, s_texConvFrameBuffer); - s_rgbToYuyvProgram.Destroy(); - s_yuyvToRgbProgram.Destroy(); - for (auto& program : s_encoding_programs) program.second.program.Destroy(); s_encoding_programs.clear(); @@ -217,7 +128,7 @@ void Shutdown() // dst_line_size, writeStride in bytes static void EncodeToRamUsingShader(GLuint srcTexture, u8* destAddr, u32 dst_line_size, - u32 dstHeight, u32 writeStride, bool linearFilter) + u32 dstHeight, u32 writeStride, bool linearFilter, float y_scale) { // switch to texture converter frame buffer // attach render buffer as color destination @@ -233,7 +144,7 @@ static void EncodeToRamUsingShader(GLuint srcTexture, u8* destAddr, u32 dst_line // TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more // complex down filtering to average all pixels and produce the correct result. // Also, box filtering won't be correct for anything other than 1x IR - if (linearFilter || g_renderer->GetEFBScale() != 1) + if (linearFilter || g_renderer->GetEFBScale() != 1 || y_scale > 1.0f) g_sampler_cache->BindLinearSampler(9); else g_sampler_cache->BindNearestSampler(9); @@ -282,76 +193,19 @@ void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 nativ texconv_shader.program.Bind(); glUniform4i(texconv_shader.copy_position_uniform, src_rect.left, src_rect.top, native_width, scale_by_half ? 2 : 1); + glUniform1f(texconv_shader.y_scale_uniform, params.y_scale); const GLuint read_texture = params.depth ? FramebufferManager::ResolveAndGetDepthTarget(src_rect) : FramebufferManager::ResolveAndGetRenderTarget(src_rect); EncodeToRamUsingShader(read_texture, dest_ptr, bytes_per_row, num_blocks_y, memory_stride, - scale_by_half && !params.depth); + scale_by_half && !params.depth, params.y_scale); FramebufferManager::SetFramebuffer(0); g_renderer->RestoreAPIState(); } -void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, u32 dstWidth, - u32 dstStride, u32 dstHeight) -{ - g_renderer->ResetAPIState(); - - s_rgbToYuyvProgram.Bind(); - - glUniform4f(s_rgbToYuyvUniform_loc, static_cast(sourceRc.left), - static_cast(sourceRc.top), static_cast(sourceRc.right), - static_cast(sourceRc.bottom)); - - // We enable linear filtering, because the GameCube does filtering in the vertical direction when - // yscale is enabled. - // Otherwise we get jaggies when a game uses yscaling (most PAL games) - EncodeToRamUsingShader(srcTexture, destAddr, dstWidth * 2, dstHeight, dstStride, true); - FramebufferManager::SetFramebuffer(0); - OGLTexture::DisableStage(0); - g_renderer->RestoreAPIState(); -} - -// Should be scale free. -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture) -{ - u8* srcAddr = Memory::GetPointer(xfbAddr); - if (!srcAddr) - { - WARN_LOG(VIDEO, "Tried to decode from invalid memory address"); - return; - } - - g_renderer->ResetAPIState(); // reset any game specific settings - - OpenGL_BindAttributelessVAO(); - - // switch to texture converter frame buffer - // attach destTexture as color destination - FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[1]); - FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, - destTexture, 0); - - // activate source texture - // set srcAddr as data for source texture - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D, s_srcTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcWidth / 2, srcHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, - srcAddr); - g_sampler_cache->BindNearestSampler(9); - - glViewport(0, 0, srcWidth, srcHeight); - s_yuyvToRgbProgram.Bind(); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - FramebufferManager::SetFramebuffer(0); - - g_renderer->RestoreAPIState(); -} - } // namespace } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.h b/Source/Core/VideoBackends/OGL/TextureConverter.h index 3b535752a3..baed715a7e 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.h +++ b/Source/Core/VideoBackends/OGL/TextureConverter.h @@ -20,11 +20,6 @@ namespace TextureConverter void Init(); void Shutdown(); -void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, u32 dstWidth, - u32 dstStride, u32 dstHeight); - -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture); - // returns size of the encoded data (in bytes) void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index 4b3a7a5daf..10d37de6bc 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -91,6 +91,8 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsReversedDepthRange = true; g_Config.backend_info.bSupportsMultithreading = false; g_Config.backend_info.bSupportsInternalResolutionFrameDumps = true; + g_Config.backend_info.bSupportsCopyToVram = true; + g_Config.backend_info.bForceCopyToRam = false; // TODO: There is a bug here, if texel buffers are not supported the graphics options // will show the option when it is not supported. The only way around this would be diff --git a/Source/Core/VideoBackends/Software/CopyRegion.h b/Source/Core/VideoBackends/Software/CopyRegion.h new file mode 100644 index 0000000000..fd695b8d3a --- /dev/null +++ b/Source/Core/VideoBackends/Software/CopyRegion.h @@ -0,0 +1,33 @@ +#pragma once + +#include "Common/MathUtil.h" + +#include + +namespace SW +{ +// Modified from +// http://tech-algorithm.com/articles/nearest-neighbor-image-scaling/ +template +void CopyRegion(const T* const source, const MathUtil::Rectangle& srcrect, T* destination, + const MathUtil::Rectangle& dstrect) +{ + double x_ratio = srcrect.GetWidth() / static_cast(dstrect.GetWidth()); + double y_ratio = srcrect.GetHeight() / static_cast(dstrect.GetHeight()); + for (int i = 0; i < dstrect.GetHeight(); i++) + { + for (int j = 0; j < dstrect.GetWidth(); j++) + { + int destination_x = j + dstrect.left; + int destination_y = i + dstrect.top; + int destination_offset = (destination_y * dstrect.GetWidth()) + destination_x; + + double src_x = std::round(destination_x * x_ratio) + srcrect.left; + double src_y = std::round(destination_y * y_ratio) + srcrect.top; + int src_offset = static_cast((src_y * srcrect.GetWidth()) + src_x); + + destination[destination_offset] = source[src_offset]; + } + } +} +} diff --git a/Source/Core/VideoBackends/Software/EfbCopy.cpp b/Source/Core/VideoBackends/Software/EfbCopy.cpp index 26afc6c779..bba64ee7c1 100644 --- a/Source/Core/VideoBackends/Software/EfbCopy.cpp +++ b/Source/Core/VideoBackends/Software/EfbCopy.cpp @@ -12,30 +12,8 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/Fifo.h" -static const float s_gammaLUT[] = {1.0f, 1.7f, 2.2f, 1.0f}; - namespace EfbCopy { -static void CopyToXfb(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma) -{ - DEBUG_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f", - xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, - sourceRc.right, Gamma); - - EfbInterface::yuv422_packed* xfb_in_ram = - (EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr); - - EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma); -} - -static void CopyToRam() -{ - u8* dest_ptr = Memory::GetPointer(bpmem.copyTexDest << 5); - - TextureEncoder::Encode(dest_ptr); -} - void ClearEfb() { u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 | @@ -55,43 +33,4 @@ void ClearEfb() } } } - -void CopyEfb() -{ - EFBRectangle rc; - rc.left = (int)bpmem.copyTexSrcXY.x; - rc.top = (int)bpmem.copyTexSrcXY.y; - - // flipper represents the widths internally as last pixel minus starting pixel, so - // these are zero indexed. - rc.right = rc.left + (int)bpmem.copyTexSrcWH.x + 1; - rc.bottom = rc.top + (int)bpmem.copyTexSrcWH.y + 1; - - if (bpmem.triggerEFBCopy.copy_to_xfb) - { - float yScale; - if (bpmem.triggerEFBCopy.scale_invert) - yScale = 256.0f / (float)bpmem.dispcopyyscale; - else - yScale = (float)bpmem.dispcopyyscale / 256.0f; - - float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale); - - if (yScale != 1.0) - WARN_LOG(VIDEO, "yScale of %f is currently unsupported", yScale); - - if ((u32)xfbLines > MAX_XFB_HEIGHT) - { - INFO_LOG(VIDEO, "Tried to scale EFB to too many XFB lines (%f)", xfbLines); - xfbLines = MAX_XFB_HEIGHT; - } - - CopyToXfb(bpmem.copyTexDest << 5, bpmem.copyMipMapStrideChannels << 4, (u32)xfbLines, rc, - s_gammaLUT[bpmem.triggerEFBCopy.gamma]); - } - else - { - CopyToRam(); // FIXME: should use the rectangle we have already created above - } -} } diff --git a/Source/Core/VideoBackends/Software/EfbCopy.h b/Source/Core/VideoBackends/Software/EfbCopy.h index 95986c1dd5..a544b3245e 100644 --- a/Source/Core/VideoBackends/Software/EfbCopy.h +++ b/Source/Core/VideoBackends/Software/EfbCopy.h @@ -6,8 +6,5 @@ namespace EfbCopy { -// Copy the EFB to RAM as a texture format or XFB -void CopyEfb(); - void ClearEfb(); } diff --git a/Source/Core/VideoBackends/Software/EfbInterface.cpp b/Source/Core/VideoBackends/Software/EfbInterface.cpp index 9f6af90c0d..a94ac467b8 100644 --- a/Source/Core/VideoBackends/Software/EfbInterface.cpp +++ b/Source/Core/VideoBackends/Software/EfbInterface.cpp @@ -7,11 +7,13 @@ #include #include #include +#include #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/Swap.h" +#include "VideoBackends/Software/CopyRegion.h" #include "VideoCommon/BPMemory.h" #include "VideoCommon/LookUpTables.h" #include "VideoCommon/PerfQueryBase.h" @@ -495,19 +497,16 @@ u8* GetPixelPointer(u16 x, u16 y, bool depth) return &efb[GetColorOffset(x, y)]; } -void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma) +void EncodeXFB(u8* xfb_in_ram, u32 memory_stride, const EFBRectangle& source_rect, float y_scale) { - // FIXME: We should do Gamma correction - if (!xfb_in_ram) { WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); return; } - int left = sourceRc.left; - int right = sourceRc.right; + int left = source_rect.left; + int right = source_rect.right; // this assumes copies will always start on an even (YU) pixel and the // copy always has an even width, which might not be true. @@ -520,16 +519,11 @@ void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRe // Scanline buffer, leave room for borders yuv444 scanline[EFB_WIDTH + 2]; - // our internal yuv444 type is not normalized, so black is {0, 0, 0} instead of {16, 128, 128} - yuv444 black; - black.Y = 0; - black.U = 0; - black.V = 0; + static std::vector source; + source.resize(EFB_WIDTH * EFB_HEIGHT); + yuv422_packed* src_ptr = &source[0]; - scanline[0] = black; // black border at start - scanline[right + 1] = black; // black border at end - - for (u16 y = sourceRc.top; y < sourceRc.bottom; y++) + for (float y = source_rect.top; y < source_rect.bottom; y++) { // Get a scanline of YUV pixels in 4:4:4 format @@ -538,50 +532,38 @@ void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRe scanline[i] = GetColorYUV(x, y); } + // Flipper clamps the border colors + scanline[0] = scanline[1]; + scanline[right + 1] = scanline[right]; + // And Downsample them to 4:2:2 for (int i = 1, x = left; x < right; i += 2, x += 2) { // YU pixel - xfb_in_ram[x].Y = scanline[i].Y + 16; + src_ptr[x].Y = scanline[i].Y + 16; // we mix our color differences in 10 bit space so it will round more accurately // U[i] = 1/4 * U[i-1] + 1/2 * U[i] + 1/4 * U[i+1] - xfb_in_ram[x].UV = - 128 + ((scanline[i - 1].U + (scanline[i].U << 1) + scanline[i + 1].U) >> 2); + src_ptr[x].UV = 128 + ((scanline[i - 1].U + (scanline[i].U << 1) + scanline[i + 1].U) >> 2); // YV pixel - xfb_in_ram[x + 1].Y = scanline[i + 1].Y + 16; + src_ptr[x + 1].Y = scanline[i + 1].Y + 16; // V[i] = 1/4 * V[i-1] + 1/2 * V[i] + 1/4 * V[i+1] - xfb_in_ram[x + 1].UV = + src_ptr[x + 1].UV = 128 + ((scanline[i].V + (scanline[i + 1].V << 1) + scanline[i + 2].V) >> 2); } - xfb_in_ram += fbWidth; - } -} - -// Like CopyToXFB, but we copy directly into the OpenGL color texture without going via GameCube -// main memory or doing a yuyv conversion -void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) -{ - if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT) - { - ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight); - return; + src_ptr += memory_stride; } - size_t textureAddress = 0; - const int left = sourceRc.left; - const int right = sourceRc.right; + auto dest_rect = EFBRectangle{source_rect.left, source_rect.top, source_rect.right, + static_cast(static_cast(source_rect.bottom) * y_scale)}; - for (u16 y = sourceRc.top; y < sourceRc.bottom; y++) - { - for (u16 x = left; x < right; x++) - { - const u32 color = Common::swap32(GetColor(x, y) | 0xFF); + const std::size_t destination_size = dest_rect.GetWidth() * dest_rect.GetHeight() * 2; + static std::vector destination; + destination.resize(dest_rect.GetWidth() * dest_rect.GetHeight()); - std::memcpy(&texture[textureAddress], &color, sizeof(u32)); - textureAddress += sizeof(u32); - } - } + SW::CopyRegion(source.data(), source_rect, destination.data(), dest_rect); + + memcpy(xfb_in_ram, destination.data(), destination_size); } bool ZCompare(u16 x, u16 y, u32 z) diff --git a/Source/Core/VideoBackends/Software/EfbInterface.h b/Source/Core/VideoBackends/Software/EfbInterface.h index 244e1fc3cf..a95d6b8aeb 100644 --- a/Source/Core/VideoBackends/Software/EfbInterface.h +++ b/Source/Core/VideoBackends/Software/EfbInterface.h @@ -57,9 +57,7 @@ u32 GetDepth(u16 x, u16 y); u8* GetPixelPointer(u16 x, u16 y, bool depth); -void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma); -void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma); +void EncodeXFB(u8* xfb_in_ram, u32 memory_stride, const EFBRectangle& source_rect, float y_scale); extern u32 perf_values[PQ_NUM_MEMBERS]; inline void IncPerfCounterQuadCount(PerfQueryType type) diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp index 9d42ff5790..8027d3fb68 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp @@ -9,6 +9,7 @@ #include "Common/Logging/Log.h" #include "VideoBackends/Software/SWOGLWindow.h" +#include "VideoBackends/Software/SWTexture.h" std::unique_ptr SWOGLWindow::s_instance; @@ -53,9 +54,9 @@ void SWOGLWindow::Prepare() std::string frag_shader = "in vec2 TexCoord;\n" "out vec4 ColorOut;\n" - "uniform sampler2D Texture;\n" + "uniform sampler2D samp;\n" "void main() {\n" - " ColorOut = texture(Texture, TexCoord);\n" + " ColorOut = texture(samp, TexCoord);\n" "}\n"; std::string vertex_shader = "out vec2 TexCoord;\n" @@ -74,10 +75,10 @@ void SWOGLWindow::Prepare() glUseProgram(m_image_program); - glUniform1i(glGetUniformLocation(m_image_program, "Texture"), 0); - + glUniform1i(glGetUniformLocation(m_image_program, "samp"), 0); glGenTextures(1, &m_image_texture); glBindTexture(GL_TEXTURE_2D, m_image_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -89,23 +90,27 @@ void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color) m_text.push_back({text, x, y, color}); } -void SWOGLWindow::ShowImage(const u8* data, int stride, int width, int height, float aspect) +void SWOGLWindow::ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region) { - GLInterface->MakeCurrent(); - GLInterface->Update(); - Prepare(); + SW::SWTexture* sw_image = static_cast(image); + GLInterface->Update(); // just updates the render window position and the backbuffer size GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth(); GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight(); glViewport(0, 0, glWidth, glHeight); + glActiveTexture(GL_TEXTURE9); glBindTexture(GL_TEXTURE_2D, m_image_texture); + // TODO: Apply xfb_region + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, data); + glPixelStorei(GL_UNPACK_ROW_LENGTH, sw_image->GetConfig().width); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast(sw_image->GetConfig().width), + static_cast(sw_image->GetConfig().height), 0, GL_RGBA, GL_UNSIGNED_BYTE, + sw_image->GetData()); glUseProgram(m_image_program); @@ -119,7 +124,6 @@ void SWOGLWindow::ShowImage(const u8* data, int stride, int width, int height, f m_text.clear(); GLInterface->Swap(); - GLInterface->ClearCurrent(); } int SWOGLWindow::PeekMessages() diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.h b/Source/Core/VideoBackends/Software/SWOGLWindow.h index 110642b3f8..64ee2414bc 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.h +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.h @@ -9,18 +9,22 @@ #include #include "Common/CommonTypes.h" +#include "VideoCommon/VideoCommon.h" + +class AbstractTexture; class SWOGLWindow { public: static void Init(void* window_handle); static void Shutdown(); + void Prepare(); // Will be printed on the *next* image void PrintText(const std::string& text, int x, int y, u32 color); // Image to show, will be swapped immediately - void ShowImage(const u8* data, int stride, int width, int height, float aspect); + void ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region); int PeekMessages(); @@ -28,8 +32,6 @@ public: private: SWOGLWindow() {} - void Prepare(); - struct TextData { std::string text; diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index dc378cbede..4f1fafd989 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -23,26 +23,13 @@ #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoConfig.h" -static u8* s_xfbColorTexture[2]; -static int s_currentColorTexture = 0; - SWRenderer::SWRenderer() : ::Renderer(static_cast(MAX_XFB_WIDTH), static_cast(MAX_XFB_HEIGHT)) { } -SWRenderer::~SWRenderer() -{ - delete[] s_xfbColorTexture[0]; - delete[] s_xfbColorTexture[1]; -} - void SWRenderer::Init() { - s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4]; - s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4]; - - s_currentColorTexture = 0; } void SWRenderer::Shutdown() @@ -55,96 +42,17 @@ void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 colo SWOGLWindow::s_instance->PrintText(pstr, left, top, color); } -u8* SWRenderer::GetNextColorTexture() -{ - return s_xfbColorTexture[!s_currentColorTexture]; -} - -u8* SWRenderer::GetCurrentColorTexture() -{ - return s_xfbColorTexture[s_currentColorTexture]; -} - -void SWRenderer::SwapColorTexture() -{ - s_currentColorTexture = !s_currentColorTexture; -} - -void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight) -{ - if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT) - { - ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight); - return; - } - - u32 offset = 0; - u8* TexturePointer = GetNextColorTexture(); - - for (u16 y = 0; y < fbHeight; y++) - { - for (u16 x = 0; x < fbWidth; x += 2) - { - // We do this one color sample (aka 2 RGB pixles) at a time - int Y1 = xfb[x].Y - 16; - int Y2 = xfb[x + 1].Y - 16; - int U = int(xfb[x].UV) - 128; - int V = int(xfb[x + 1].UV) - 128; - - // We do the inverse BT.601 conversion for YCbCr to RGB - // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255); - TexturePointer[offset++] = - MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255); - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U), 0, 255); - TexturePointer[offset++] = 255; - - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255); - TexturePointer[offset++] = - MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255); - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U), 0, 255); - TexturePointer[offset++] = 255; - } - xfb += fbWidth; - } - SwapColorTexture(); -} - // Called on the GPU thread -void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, - const EFBRectangle& rc, u64 ticks, float Gamma) +void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks, + float Gamma) { - if (g_ActiveConfig.bUseXFB) - { - EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr); - UpdateColorTexture(xfb, fbWidth, fbHeight); - } - else - { - EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma); - } - - // Save screenshot - if (IsFrameDumping()) - { - AVIDump::Frame state = AVIDump::FetchState(ticks); - DumpFrameData(GetCurrentColorTexture(), fbWidth, fbHeight, fbWidth * 4, state); - FinishFrameData(); - } - OSD::DoCallbacks(OSD::CallbackType::OnFrame); DrawDebugText(); - SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0); + SWOGLWindow::s_instance->ShowImage(texture, xfb_region); UpdateActiveConfig(); - - // virtual XFB is not supported - if (g_ActiveConfig.bUseXFB) - { - Config::SetCurrent(Config::GFX_USE_REAL_XFB, true); - } } u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) diff --git a/Source/Core/VideoBackends/Software/SWRenderer.h b/Source/Core/VideoBackends/Software/SWRenderer.h index b19b9841fd..e30e490bd7 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.h +++ b/Source/Core/VideoBackends/Software/SWRenderer.h @@ -14,16 +14,10 @@ class SWRenderer : public Renderer { public: SWRenderer(); - ~SWRenderer() override; static void Init(); static void Shutdown(); - static u8* GetNextColorTexture(); - static u8* GetCurrentColorTexture(); - void SwapColorTexture(); - void UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight); - void RenderText(const std::string& pstr, int left, int top, u32 color) override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {} @@ -32,8 +26,7 @@ public: TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, - u64 ticks, float Gamma) override; + void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override; void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; diff --git a/Source/Core/VideoBackends/Software/SWTexture.cpp b/Source/Core/VideoBackends/Software/SWTexture.cpp index 164c0d5314..aa279b520b 100644 --- a/Source/Core/VideoBackends/Software/SWTexture.cpp +++ b/Source/Core/VideoBackends/Software/SWTexture.cpp @@ -4,10 +4,27 @@ #include "VideoBackends/Software/SWTexture.h" +#include + +#include "VideoBackends/Software/CopyRegion.h" + namespace SW { +namespace +{ +#pragma pack(push, 1) +struct Pixel +{ + u8 r; + u8 g; + u8 b; + u8 a; +}; +#pragma pack(pop) +} SWTexture::SWTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config) { + m_data.resize(tex_config.width * tex_config.height * 4); } void SWTexture::Bind(unsigned int stage) @@ -18,11 +35,47 @@ void SWTexture::CopyRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, const MathUtil::Rectangle& dstrect) { + const SWTexture* software_source_texture = static_cast(source); + + if (srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight()) + { + m_data.assign(software_source_texture->GetData(), + software_source_texture->GetData() + m_data.size()); + } + else + { + std::vector source_pixels; + source_pixels.resize(srcrect.GetHeight() * srcrect.GetWidth() * 4); + memcpy(source_pixels.data(), software_source_texture->GetData(), source_pixels.size()); + + std::vector destination_pixels; + destination_pixels.resize(dstrect.GetHeight() * dstrect.GetWidth() * 4); + + CopyRegion(source_pixels.data(), srcrect, destination_pixels.data(), dstrect); + memcpy(GetData(), destination_pixels.data(), destination_pixels.size()); + } } void SWTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) { + m_data.assign(buffer, buffer + buffer_size); +} + +const u8* SWTexture::GetData() const +{ + return m_data.data(); +} + +u8* SWTexture::GetData() +{ + return m_data.data(); +} + +std::optional SWTexture::MapFullImpl() +{ + return AbstractTexture::RawTextureInfo{GetData(), m_config.width * 4, m_config.width, + m_config.height}; } } // namespace SW diff --git a/Source/Core/VideoBackends/Software/SWTexture.h b/Source/Core/VideoBackends/Software/SWTexture.h index 4d6189bb4f..fa7fea5308 100644 --- a/Source/Core/VideoBackends/Software/SWTexture.h +++ b/Source/Core/VideoBackends/Software/SWTexture.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "Common/CommonTypes.h" #include "VideoCommon/AbstractTexture.h" @@ -23,6 +25,14 @@ public: const MathUtil::Rectangle& dstrect) override; void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) override; + + const u8* GetData() const; + u8* GetData(); + +private: + std::optional MapFullImpl() override; + + std::vector m_data; }; } // namespace SW diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp index dff26e6d86..c2bbafb420 100644 --- a/Source/Core/VideoBackends/Software/SWmain.cpp +++ b/Source/Core/VideoBackends/Software/SWmain.cpp @@ -8,16 +8,17 @@ #include #include "Common/CommonTypes.h" +#include "Common/GL/GLInterfaceBase.h" #include "VideoBackends/Software/Clipper.h" #include "VideoBackends/Software/DebugUtil.h" -#include "VideoBackends/Software/EfbCopy.h" #include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/Rasterizer.h" #include "VideoBackends/Software/SWOGLWindow.h" #include "VideoBackends/Software/SWRenderer.h" #include "VideoBackends/Software/SWTexture.h" #include "VideoBackends/Software/SWVertexLoader.h" +#include "VideoBackends/Software/TextureCache.h" #include "VideoBackends/Software/VideoBackend.h" #include "VideoCommon/FramebufferManagerBase.h" @@ -46,58 +47,6 @@ public: bool IsFlushed() const override { return true; } }; -class TextureCache : public TextureCacheBase -{ -public: - bool CompileShaders() override { return true; } - void DeleteShaders() override {} - void ConvertTexture(TCacheEntry* entry, TCacheEntry* unconverted, const void* palette, - TLUTFormat format) override - { - } - void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, - bool scale_by_half) override - { - EfbCopy::CopyEfb(); - } - -private: - std::unique_ptr CreateTexture(const TextureConfig& config) override - { - return std::make_unique(config); - } - - void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect, - bool scale_by_half, unsigned int cbuf_id, const float* colmat) override - { - EfbCopy::CopyEfb(); - } -}; - -class XFBSource : public XFBSourceBase -{ - void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override {} - void CopyEFB(float Gamma) override {} -}; - -class FramebufferManager : public FramebufferManagerBase -{ - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override - { - return std::make_unique(); - } - - std::pair GetTargetSize() const override { return std::make_pair(0, 0); } - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma = 1.0f) override - { - EfbCopy::CopyEfb(); - } -}; - std::string VideoSoftware::GetName() const { return "Software Renderer"; @@ -123,6 +72,8 @@ void VideoSoftware::InitBackendInfo() g_Config.backend_info.bSupportsGPUTextureDecoding = false; g_Config.backend_info.bSupportsST3CTextures = false; g_Config.backend_info.bSupportsBPTCTextures = false; + g_Config.backend_info.bSupportsCopyToVram = false; + g_Config.backend_info.bForceCopyToRam = true; // aamodes g_Config.backend_info.AAModes = {1}; @@ -169,12 +120,14 @@ void VideoSoftware::Video_Cleanup() // This is called after Video_Initialize() from the Core void VideoSoftware::Video_Prepare() { + GLInterface->MakeCurrent(); + SWOGLWindow::s_instance->Prepare(); + g_renderer = std::make_unique(); g_vertex_manager = std::make_unique(); g_perf_query = std::make_unique(); g_texture_cache = std::make_unique(); SWRenderer::Init(); - g_framebuffer_manager = std::make_unique(); } unsigned int VideoSoftware::PeekMessages() diff --git a/Source/Core/VideoBackends/Software/Software.vcxproj b/Source/Core/VideoBackends/Software/Software.vcxproj index bf13233d67..9a1a992900 100644 --- a/Source/Core/VideoBackends/Software/Software.vcxproj +++ b/Source/Core/VideoBackends/Software/Software.vcxproj @@ -54,6 +54,7 @@ + @@ -65,6 +66,7 @@ + diff --git a/Source/Core/VideoBackends/Software/TextureCache.h b/Source/Core/VideoBackends/Software/TextureCache.h new file mode 100644 index 0000000000..3573d36ebb --- /dev/null +++ b/Source/Core/VideoBackends/Software/TextureCache.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include "VideoBackends/Software/SWTexture.h" +#include "VideoBackends/Software/TextureEncoder.h" +#include "VideoCommon/TextureCacheBase.h" + +namespace SW +{ +class TextureCache : public TextureCacheBase +{ +public: + bool CompileShaders() override { return true; } + void DeleteShaders() override {} + void ConvertTexture(TCacheEntry* entry, TCacheEntry* unconverted, const void* palette, + TLUTFormat format) override + { + } + void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, + bool scale_by_half) override + { + TextureEncoder::Encode(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride, + src_rect, scale_by_half); + } + +private: + std::unique_ptr CreateTexture(const TextureConfig& config) override + { + return std::make_unique(config); + } + + void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect, + bool scale_by_half, unsigned int cbuf_id, const float* colmat) override + { + // TODO: If we ever want to "fake" vram textures, we would need to implement this + } +}; + +} // namespace SW diff --git a/Source/Core/VideoBackends/Software/TextureEncoder.cpp b/Source/Core/VideoBackends/Software/TextureEncoder.cpp index 6181d56dd4..4d0997ebf5 100644 --- a/Source/Core/VideoBackends/Software/TextureEncoder.cpp +++ b/Source/Core/VideoBackends/Software/TextureEncoder.cpp @@ -14,6 +14,7 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/LookUpTables.h" +#include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureDecoder.h" namespace TextureEncoder @@ -1416,37 +1417,64 @@ static void EncodeZ24halfscale(u8* dst, const u8* src, EFBCopyFormat format) } } -void Encode(u8* dest_ptr) +namespace { - auto pixelformat = bpmem.zcontrol.pixel_format; - bool bFromZBuffer = pixelformat == PEControl::Z24; - bool bIsIntensityFmt = bpmem.triggerEFBCopy.intensity_fmt > 0; - EFBCopyFormat copyfmt = bpmem.triggerEFBCopy.tp_realFormat(); +void EncodeEfbCopy(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, + bool scale_by_half) +{ + const u8* src = EfbInterface::GetPixelPointer(src_rect.left, src_rect.top, params.depth); - const u8* src = - EfbInterface::GetPixelPointer(bpmem.copyTexSrcXY.x, bpmem.copyTexSrcXY.y, bFromZBuffer); - - if (bpmem.triggerEFBCopy.half_scale) + if (scale_by_half) { - if (pixelformat == PEControl::RGBA6_Z24) - EncodeRGBA6halfscale(dest_ptr, src, copyfmt, bIsIntensityFmt); - else if (pixelformat == PEControl::RGB8_Z24) - EncodeRGB8halfscale(dest_ptr, src, copyfmt, bIsIntensityFmt); - else if (pixelformat == PEControl::RGB565_Z16) // not supported - EncodeRGB8halfscale(dest_ptr, src, copyfmt, bIsIntensityFmt); - else if (pixelformat == PEControl::Z24) - EncodeZ24halfscale(dest_ptr, src, copyfmt); + switch (params.efb_format) + { + case PEControl::RGBA6_Z24: + EncodeRGBA6halfscale(dst, src, params.copy_format, params.yuv); + break; + case PEControl::RGB8_Z24: + EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv); + break; + case PEControl::RGB565_Z16: + EncodeRGB8halfscale(dst, src, params.copy_format, params.yuv); + break; + case PEControl::Z24: + EncodeZ24halfscale(dst, src, params.copy_format); + break; + } } else { - if (pixelformat == PEControl::RGBA6_Z24) - EncodeRGBA6(dest_ptr, src, copyfmt, bIsIntensityFmt); - else if (pixelformat == PEControl::RGB8_Z24) - EncodeRGB8(dest_ptr, src, copyfmt, bIsIntensityFmt); - else if (pixelformat == PEControl::RGB565_Z16) // not supported - EncodeRGB8(dest_ptr, src, copyfmt, bIsIntensityFmt); - else if (pixelformat == PEControl::Z24) - EncodeZ24(dest_ptr, src, copyfmt); + switch (params.efb_format) + { + case PEControl::RGBA6_Z24: + EncodeRGBA6(dst, src, params.copy_format, params.yuv); + break; + case PEControl::RGB8_Z24: + EncodeRGB8(dst, src, params.copy_format, params.yuv); + break; + case PEControl::RGB565_Z16: + EncodeRGB8(dst, src, params.copy_format, params.yuv); + break; + case PEControl::Z24: + EncodeZ24(dst, src, params.copy_format); + break; + } + } +} +} + +void Encode(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half) +{ + if (params.copy_format == EFBCopyFormat::XFB) + { + EfbInterface::EncodeXFB(dst, native_width, src_rect, params.y_scale); + } + else + { + EncodeEfbCopy(dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride, src_rect, + scale_by_half); } } } diff --git a/Source/Core/VideoBackends/Software/TextureEncoder.h b/Source/Core/VideoBackends/Software/TextureEncoder.h index 32bc9d10cd..ec21c97c42 100644 --- a/Source/Core/VideoBackends/Software/TextureEncoder.h +++ b/Source/Core/VideoBackends/Software/TextureEncoder.h @@ -5,8 +5,12 @@ #pragma once #include "Common/CommonTypes.h" +#include "VideoCommon/VideoCommon.h" + +struct EFBCopyParams; namespace TextureEncoder { -void Encode(u8* dest_ptr); +void Encode(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half); } diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 53351e0325..305f0343f7 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -89,11 +89,6 @@ MultisamplingState FramebufferManager::GetEFBMultisamplingState() const return ms; } -std::pair FramebufferManager::GetTargetSize() const -{ - return std::make_pair(GetEFBWidth(), GetEFBHeight()); -} - bool FramebufferManager::Initialize() { if (!CreateEFBRenderPass()) @@ -1382,102 +1377,4 @@ void FramebufferManager::DestroyPokeShaders() } } -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) -{ - TextureConfig config; - config.width = target_width; - config.height = target_height; - config.layers = layers; - config.rendertarget = true; - auto texture = TextureCache::GetInstance()->CreateTexture(config); - if (!texture) - { - PanicAlert("Failed to create texture for XFB source"); - return nullptr; - } - - return std::make_unique(std::move(texture)); -} - -void FramebufferManager::CopyToRealXFB(u32 xfb_addr, u32 fb_stride, u32 fb_height, - const EFBRectangle& source_rc, float gamma) -{ - // Pending/batched EFB pokes should be included in the copied image. - FlushEFBPokes(); - - // Schedule early command-buffer execution. - StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnReadback(); - - // GPU EFB textures -> Guest memory - u8* xfb_ptr = Memory::GetPointer(xfb_addr); - _assert_(xfb_ptr); - - // source_rc is in native coordinates, so scale it to the internal resolution. - TargetRectangle scaled_rc = g_renderer->ConvertEFBRectangle(source_rc); - VkRect2D scaled_rc_vk = { - {scaled_rc.left, scaled_rc.top}, - {static_cast(scaled_rc.GetWidth()), static_cast(scaled_rc.GetHeight())}}; - Texture2D* src_texture = ResolveEFBColorTexture(scaled_rc_vk); - - // The destination stride can differ from the copy region width, in which case the pixels - // outside the copy region should not be written to. - TextureCache::GetInstance()->GetTextureConverter()->EncodeTextureToMemoryYUYV( - xfb_ptr, static_cast(source_rc.GetWidth()), fb_stride, fb_height, src_texture, - scaled_rc); - - // If we sourced directly from the EFB framebuffer, restore it to a color attachment. - if (src_texture == m_efb_color_texture.get()) - { - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } -} - -XFBSource::XFBSource(std::unique_ptr texture) - : XFBSourceBase(), m_texture(std::move(texture)) -{ -} - -XFBSource::~XFBSource() -{ -} - -VKTexture* XFBSource::GetTexture() const -{ - return static_cast(m_texture.get()); -} - -void XFBSource::DecodeToTexture(u32 xfb_addr, u32 fb_width, u32 fb_height) -{ - // Guest memory -> GPU EFB Textures - const u8* src_ptr = Memory::GetPointer(xfb_addr); - _assert_(src_ptr); - TextureCache::GetInstance()->GetTextureConverter()->DecodeYUYVTextureFromMemory( - static_cast(m_texture.get()), src_ptr, fb_width, fb_width * 2, fb_height); -} - -void XFBSource::CopyEFB(float gamma) -{ - // Pending/batched EFB pokes should be included in the copied image. - FramebufferManager::GetInstance()->FlushEFBPokes(); - - // Virtual XFB, copy EFB at native resolution to m_texture - MathUtil::Rectangle rect(0, 0, static_cast(texWidth), static_cast(texHeight)); - VkRect2D vk_rect = {{rect.left, rect.top}, - {static_cast(rect.GetWidth()), static_cast(rect.GetHeight())}}; - - Texture2D* src_texture = FramebufferManager::GetInstance()->ResolveEFBColorTexture(vk_rect); - static_cast(m_texture.get())->CopyRectangleFromTexture(src_texture, rect, rect); - - // If we sourced directly from the EFB framebuffer, restore it to a color attachment. - if (src_texture == FramebufferManager::GetInstance()->GetEFBColorTexture()) - { - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } -} - } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h index ca7065c3bb..0c1a160728 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h @@ -43,15 +43,6 @@ public: u32 GetEFBLayers() const; VkSampleCountFlagBits GetEFBSamples() const; MultisamplingState GetEFBMultisamplingState() const; - std::pair GetTargetSize() const override; - - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override; - - // GPU EFB textures -> Guest - void CopyToRealXFB(u32 xfb_addr, u32 fb_stride, u32 fb_height, const EFBRectangle& source_rc, - float gamma = 1.0f) override; void ResizeEFBTextures(); @@ -169,23 +160,4 @@ private: VkShaderModule m_poke_fragment_shader = VK_NULL_HANDLE; }; -// The XFB source class simply wraps a texture cache entry. -// All the required functionality is provided by TextureCache. -class XFBSource final : public XFBSourceBase -{ -public: - explicit XFBSource(std::unique_ptr texture); - ~XFBSource(); - - VKTexture* GetTexture() const; - // Guest -> GPU EFB Textures - void DecodeToTexture(u32 xfb_addr, u32 fb_width, u32 fb_height) override; - - // Used for virtual XFB - void CopyEFB(float gamma) override; - -private: - std::unique_ptr m_texture; -}; - } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 3a4907b88c..d72f2929c3 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -41,6 +41,7 @@ #include "VideoCommon/SamplerCommon.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/VideoBackendBase.h" +#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" #include "VideoCommon/XFMemory.h" @@ -60,11 +61,6 @@ Renderer::~Renderer() { UpdateActiveConfig(); - // Ensure all frames are written to frame dump at shutdown. - if (m_frame_dumping_active) - EndFrameDumping(); - - DestroyFrameDumpResources(); DestroyShaders(); DestroySemaphores(); } @@ -485,26 +481,13 @@ void Renderer::ReinterpretPixelData(unsigned int convtype) BindEFBToStateTracker(); } -void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, - const EFBRectangle& rc, u64 ticks, float gamma) +void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks, + float Gamma) { // Pending/batched EFB pokes should be included in the final image. FramebufferManager::GetInstance()->FlushEFBPokes(); - // Check that we actually have an image to render in XFB-on modes. - if ((!m_xfb_written && !g_ActiveConfig.RealXFBEnabled()) || !fb_width || !fb_height) - { - Core::Callback_VideoCopiedToXFB(false); - return; - } - u32 xfb_count = 0; - const XFBSourceBase* const* xfb_sources = - FramebufferManager::GetXFBSource(xfb_addr, fb_stride, fb_height, &xfb_count); - if (g_ActiveConfig.VirtualXFBEnabled() && (!xfb_sources || xfb_count == 0)) - { - Core::Callback_VideoCopiedToXFB(false); - return; - } + auto* xfb_texture = static_cast(texture); // End the current render pass. StateTracker::GetInstance()->EndRenderPass(); @@ -514,31 +497,6 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height // are determined by guest state. Currently, the only way to catch these is to update every frame. UpdateDrawRectangle(); - // Scale the source rectangle to the internal resolution when XFB is disabled. - TargetRectangle scaled_efb_rect = Renderer::ConvertEFBRectangle(rc); - - // If MSAA is enabled, and we're not using XFB, we need to resolve the EFB framebuffer before - // rendering the final image to the screen, or dumping the frame. This is because we can't resolve - // an image within a render pass, which will have already started by the time it is used. - TransitionBuffersForSwap(scaled_efb_rect, xfb_sources, xfb_count); - - // Render the frame dump image if enabled. - if (IsFrameDumping()) - { - // If we haven't dumped a single frame yet, set up frame dumping. - if (!m_frame_dumping_active) - StartFrameDumping(); - - DrawFrameDump(scaled_efb_rect, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, fb_height, - ticks); - } - else - { - // If frame dumping was previously enabled, flush all frames and remove the fence callback. - if (m_frame_dumping_active) - EndFrameDumping(); - } - // Ensure the worker thread is not still submitting a previous command buffer. // In other words, the last frame has been submitted (otherwise the next call would // be a race, as the image may not have been consumed yet). @@ -547,7 +505,7 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height // Draw to the screen if we have a swap chain. if (m_swap_chain) { - DrawScreen(scaled_efb_rect, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, fb_height); + DrawScreen(xfb_texture, xfb_region); // Submit the current command buffer, signaling rendering finished semaphore when it's done // Because this final command buffer is rendering to the swap chain, we need to wait for @@ -581,15 +539,12 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height // Handle host window resizes. CheckForSurfaceChange(); - // Handle output size changes from the guest. - // There is a downside to doing this here is that if the game changes its XFB source area, - // the changes will be delayed by one frame. For the moment it has to be done here because - // this can cause a target size change, which would result in a black frame if done earlier. - CheckForTargetResize(fb_width, fb_stride, fb_height); + if (CalculateTargetSize()) + ResizeEFBTextures(); // Update the window size based on the frame that was just rendered. // Due to depending on guest state, we need to call this every frame. - SetWindowSize(static_cast(fb_stride), static_cast(fb_height)); + SetWindowSize(xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); // Clean up stale textures. TextureCache::GetInstance()->Cleanup(frameCount); @@ -598,125 +553,7 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height g_shader_cache->RetrieveAsyncShaders(); } -void Renderer::TransitionBuffersForSwap(const TargetRectangle& scaled_rect, - const XFBSourceBase* const* xfb_sources, u32 xfb_count) -{ - VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - - if (!g_ActiveConfig.bUseXFB) - { - // Drawing EFB direct. - if (g_ActiveConfig.iMultisamples > 1) - { - // While the source rect can be out-of-range when drawing, the resolve rectangle must be - // within the bounds of the texture. - VkRect2D region = { - {scaled_rect.left, scaled_rect.top}, - {static_cast(scaled_rect.GetWidth()), static_cast(scaled_rect.GetHeight())}}; - region = Util::ClampRect2D(region, FramebufferManager::GetInstance()->GetEFBWidth(), - FramebufferManager::GetInstance()->GetEFBHeight()); - - Vulkan::Texture2D* rtex = FramebufferManager::GetInstance()->ResolveEFBColorTexture(region); - rtex->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - } - else - { - FramebufferManager::GetInstance()->GetEFBColorTexture()->TransitionToLayout( - command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - } - - return; - } - - // Drawing XFB sources, so transition all of them. - // Don't need the EFB, so leave it as-is. - for (u32 i = 0; i < xfb_count; i++) - { - const XFBSource* xfb_source = static_cast(xfb_sources[i]); - xfb_source->GetTexture()->GetRawTexIdentifier()->TransitionToLayout( - command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - } -} - -void Renderer::DrawFrame(VkRenderPass render_pass, const TargetRectangle& target_rect, - const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height) -{ - if (!g_ActiveConfig.bUseXFB) - DrawEFB(render_pass, target_rect, scaled_efb_rect); - else if (!g_ActiveConfig.bUseRealXFB) - DrawVirtualXFB(render_pass, target_rect, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, - fb_height); - else - DrawRealXFB(render_pass, target_rect, xfb_sources, xfb_count, fb_width, fb_stride, fb_height); -} - -void Renderer::DrawEFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - const TargetRectangle& scaled_efb_rect) -{ - // Transition the EFB render target to a shader resource. - Texture2D* efb_color_texture = - g_ActiveConfig.iMultisamples > 1 ? - FramebufferManager::GetInstance()->GetResolvedEFBColorTexture() : - FramebufferManager::GetInstance()->GetEFBColorTexture(); - - // Copy EFB -> backbuffer - BlitScreen(render_pass, target_rect, scaled_efb_rect, efb_color_texture); -} - -void Renderer::DrawVirtualXFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - u32 xfb_addr, const XFBSourceBase* const* xfb_sources, u32 xfb_count, - u32 fb_width, u32 fb_stride, u32 fb_height) -{ - for (u32 i = 0; i < xfb_count; ++i) - { - const XFBSource* xfb_source = static_cast(xfb_sources[i]); - TargetRectangle source_rect = xfb_source->sourceRc; - TargetRectangle draw_rect; - - int xfb_width = static_cast(xfb_source->srcWidth); - int xfb_height = static_cast(xfb_source->srcHeight); - int h_offset = (static_cast(xfb_source->srcAddr) - static_cast(xfb_addr)) / - (static_cast(fb_stride) * 2); - draw_rect.top = - target_rect.top + h_offset * target_rect.GetHeight() / static_cast(fb_height); - draw_rect.bottom = - target_rect.top + - (h_offset + xfb_height) * target_rect.GetHeight() / static_cast(fb_height); - draw_rect.left = target_rect.left + - (target_rect.GetWidth() - - xfb_width * target_rect.GetWidth() / static_cast(fb_stride)) / - 2; - draw_rect.right = target_rect.left + - (target_rect.GetWidth() + - xfb_width * target_rect.GetWidth() / static_cast(fb_stride)) / - 2; - - source_rect.right -= Renderer::EFBToScaledX(fb_stride - fb_width); - BlitScreen(render_pass, draw_rect, source_rect, - xfb_source->GetTexture()->GetRawTexIdentifier()); - } -} - -void Renderer::DrawRealXFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height) -{ - for (u32 i = 0; i < xfb_count; ++i) - { - const XFBSource* xfb_source = static_cast(xfb_sources[i]); - TargetRectangle source_rect = xfb_source->sourceRc; - TargetRectangle draw_rect = target_rect; - source_rect.right -= fb_stride - fb_width; - BlitScreen(render_pass, draw_rect, source_rect, - xfb_source->GetTexture()->GetRawTexIdentifier()); - } -} - -void Renderer::DrawScreen(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height) +void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region) { VkResult res; if (!g_command_buffer_mgr->CheckLastPresentFail()) @@ -767,9 +604,10 @@ void Renderer::DrawScreen(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &info, VK_SUBPASS_CONTENTS_INLINE); - // Draw guest buffers (EFB or XFB) - DrawFrame(m_swap_chain->GetRenderPass(), GetTargetRectangle(), scaled_efb_rect, xfb_addr, - xfb_sources, xfb_count, fb_width, fb_stride, fb_height); + // Draw + TargetRectangle source_rc = xfb_texture->GetConfig().GetRect(); + BlitScreen(m_swap_chain->GetRenderPass(), GetTargetRectangle(), xfb_region, + xfb_texture->GetRawTexIdentifier()); // Draw OSD Util::SetViewportAndScissor(g_command_buffer_mgr->GetCurrentCommandBuffer(), 0, 0, @@ -787,173 +625,6 @@ void Renderer::DrawScreen(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } -bool Renderer::DrawFrameDump(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height, u64 ticks) -{ - TargetRectangle target_rect = CalculateFrameDumpDrawRectangle(); - u32 width = std::max(1u, static_cast(target_rect.GetWidth())); - u32 height = std::max(1u, static_cast(target_rect.GetHeight())); - if (!ResizeFrameDumpBuffer(width, height)) - return false; - - // If there was a previous frame dumped, we'll still be in TRANSFER_SRC layout. - m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; - VkClearRect clear_rect = {{{0, 0}, {width, height}}, 0, 1}; - VkClearAttachment clear_attachment = {VK_IMAGE_ASPECT_COLOR_BIT, 0, clear_value}; - VkRenderPassBeginInfo info = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - nullptr, - FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(), - m_frame_dump_framebuffer, - {{0, 0}, {width, height}}, - 1, - &clear_value}; - vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &info, - VK_SUBPASS_CONTENTS_INLINE); - vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), 1, &clear_attachment, 1, - &clear_rect); - DrawFrame(FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(), target_rect, - scaled_efb_rect, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, fb_height); - vkCmdEndRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer()); - - // Prepare the readback texture for copying. - StagingTexture2D* readback_texture = PrepareFrameDumpImage(width, height, ticks); - if (!readback_texture) - return false; - - // Queue a copy to the current frame dump buffer. It will be written to the frame dump later. - m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - readback_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), - m_frame_dump_render_texture->GetImage(), - VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, width, height, 0, 0); - return true; -} - -void Renderer::StartFrameDumping() -{ - _assert_(!m_frame_dumping_active); - - // Register fence callback so that we know when frames are ready to be written to the dump. - // This is done by clearing the fence pointer, so WriteFrameDumpFrame doesn't have to wait. - auto queued_callback = [](VkCommandBuffer, VkFence) {}; - auto signaled_callback = std::bind(&Renderer::OnFrameDumpImageReady, this, std::placeholders::_1); - - // We use the array pointer as a key here, that way if Renderer needed fence callbacks in - // the future it could be used without conflicting. - // We're not interested in when fences are submitted, so the first callback is a no-op. - g_command_buffer_mgr->AddFencePointCallback( - m_frame_dump_images.data(), std::move(queued_callback), std::move(signaled_callback)); - m_frame_dumping_active = true; -} - -void Renderer::EndFrameDumping() -{ - _assert_(m_frame_dumping_active); - - // Write any pending frames to the frame dump. - FlushFrameDump(); - - // Remove the fence callback that we registered earlier, one less function that needs to be - // called when preparing a command buffer. - g_command_buffer_mgr->RemoveFencePointCallback(m_frame_dump_images.data()); - m_frame_dumping_active = false; -} - -void Renderer::OnFrameDumpImageReady(VkFence fence) -{ - for (FrameDumpImage& frame : m_frame_dump_images) - { - // fence being a null handle means that we don't have to wait to re-use this image. - if (frame.fence == fence) - frame.fence = VK_NULL_HANDLE; - } -} - -void Renderer::WriteFrameDumpImage(size_t index) -{ - FrameDumpImage& frame = m_frame_dump_images[index]; - _assert_(frame.pending); - - // Check fence has been signaled. - // The callback here should set fence to null. - if (frame.fence != VK_NULL_HANDLE) - { - g_command_buffer_mgr->WaitForFence(frame.fence); - _assert_(frame.fence == VK_NULL_HANDLE); - } - - // Copy the now-populated image data to the output file. - DumpFrameData(reinterpret_cast(frame.readback_texture->GetMapPointer()), - static_cast(frame.readback_texture->GetWidth()), - static_cast(frame.readback_texture->GetHeight()), - static_cast(frame.readback_texture->GetRowStride()), frame.dump_state); - - frame.pending = false; -} - -StagingTexture2D* Renderer::PrepareFrameDumpImage(u32 width, u32 height, u64 ticks) -{ - // Ensure the last frame that was sent to the frame dump has completed encoding before we send - // the next image to it. - FinishFrameData(); - - // If the last image hasn't been written to the frame dump yet, write it now. - // This is necessary so that the worker thread is no more than one frame behind, and the pointer - // (which is actually the buffer) is safe for us to re-use next time. - if (m_frame_dump_images[m_current_frame_dump_image].pending) - WriteFrameDumpImage(m_current_frame_dump_image); - - // Move to the next image buffer - m_current_frame_dump_image = (m_current_frame_dump_image + 1) % FRAME_DUMP_BUFFERED_FRAMES; - FrameDumpImage& image = m_frame_dump_images[m_current_frame_dump_image]; - - // Ensure the dimensions of the readback texture are sufficient. - if (!image.readback_texture || width != image.readback_texture->GetWidth() || - height != image.readback_texture->GetHeight()) - { - // Allocate a new readback texture. - // The reset() call is here so that the memory is released before allocating the new texture. - image.readback_texture.reset(); - image.readback_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, width, height, - EFB_COLOR_TEXTURE_FORMAT); - - if (!image.readback_texture || !image.readback_texture->Map()) - { - // Not actually fatal, just means we can't dump this frame. - PanicAlert("Failed to allocate frame dump readback texture."); - image.readback_texture.reset(); - return nullptr; - } - } - - // The copy happens immediately after this function returns, so flag this frame as pending. - image.fence = g_command_buffer_mgr->GetCurrentCommandBufferFence(); - image.dump_state = AVIDump::FetchState(ticks); - image.pending = true; - return image.readback_texture.get(); -} - -void Renderer::FlushFrameDump() -{ - // We must write frames in order, so this is why we use a counter rather than a range. - for (size_t i = 0; i < FRAME_DUMP_BUFFERED_FRAMES; i++) - { - if (m_frame_dump_images[m_current_frame_dump_image].pending) - WriteFrameDumpImage(m_current_frame_dump_image); - - m_current_frame_dump_image = (m_current_frame_dump_image + 1) % FRAME_DUMP_BUFFERED_FRAMES; - } - - // Since everything has been written now, may as well start at index zero. - // count-1 here because the index is incremented before usage. - m_current_frame_dump_image = FRAME_DUMP_BUFFERED_FRAMES - 1; -} - void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect, const TargetRectangle& src_rect, const Texture2D* src_tex) { @@ -977,100 +648,6 @@ void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_r } } -bool Renderer::ResizeFrameDumpBuffer(u32 new_width, u32 new_height) -{ - if (m_frame_dump_render_texture && m_frame_dump_render_texture->GetWidth() == new_width && - m_frame_dump_render_texture->GetHeight() == new_height) - { - return true; - } - - // Ensure all previous frames have been dumped, since we are destroying a framebuffer - // that may still be in use. - FlushFrameDump(); - - if (m_frame_dump_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_frame_dump_framebuffer, nullptr); - m_frame_dump_framebuffer = VK_NULL_HANDLE; - } - - m_frame_dump_render_texture = - Texture2D::Create(new_width, new_height, 1, 1, EFB_COLOR_TEXTURE_FORMAT, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - - if (!m_frame_dump_render_texture) - { - WARN_LOG(VIDEO, "Failed to resize frame dump render texture"); - m_frame_dump_render_texture.reset(); - return false; - } - - VkImageView attachment = m_frame_dump_render_texture->GetView(); - VkFramebufferCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - info.renderPass = FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(); - info.attachmentCount = 1; - info.pAttachments = &attachment; - info.width = new_width; - info.height = new_height; - info.layers = 1; - - VkResult res = - vkCreateFramebuffer(g_vulkan_context->GetDevice(), &info, nullptr, &m_frame_dump_framebuffer); - if (res != VK_SUCCESS) - { - WARN_LOG(VIDEO, "Failed to create frame dump framebuffer"); - m_frame_dump_render_texture.reset(); - return false; - } - - // Render pass expects texture is in transfer src to start with. - m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - - return true; -} - -void Renderer::DestroyFrameDumpResources() -{ - if (m_frame_dump_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_frame_dump_framebuffer, nullptr); - m_frame_dump_framebuffer = VK_NULL_HANDLE; - } - - m_frame_dump_render_texture.reset(); - - for (FrameDumpImage& image : m_frame_dump_images) - { - image.readback_texture.reset(); - image.fence = VK_NULL_HANDLE; - image.dump_state = {}; - image.pending = false; - } - m_current_frame_dump_image = FRAME_DUMP_BUFFERED_FRAMES - 1; -} - -void Renderer::CheckForTargetResize(u32 fb_width, u32 fb_stride, u32 fb_height) -{ - if (FramebufferManagerBase::LastXfbWidth() == fb_stride && - FramebufferManagerBase::LastXfbHeight() == fb_height) - { - return; - } - - u32 new_width = (fb_stride < 1 || fb_stride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fb_stride; - u32 new_height = (fb_height < 1 || fb_height > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fb_height; - FramebufferManagerBase::SetLastXfbWidth(new_width); - FramebufferManagerBase::SetLastXfbHeight(new_height); - - // Changing the XFB source area may alter the target size. - if (CalculateTargetSize()) - ResizeEFBTextures(); -} - void Renderer::CheckForSurfaceChange() { if (!m_surface_needs_change.IsSet()) @@ -1144,8 +721,6 @@ void Renderer::CheckForConfigChanges() int old_aspect_ratio = g_ActiveConfig.iAspectRatio; int old_efb_scale = g_ActiveConfig.iEFBScale; bool old_force_filtering = g_ActiveConfig.bForceFiltering; - bool old_use_xfb = g_ActiveConfig.bUseXFB; - bool old_use_realxfb = g_ActiveConfig.bUseRealXFB; // Copy g_Config to g_ActiveConfig. // NOTE: This can potentially race with the UI thread, however if it does, the changes will be @@ -1157,14 +732,12 @@ void Renderer::CheckForConfigChanges() bool force_texture_filtering_changed = old_force_filtering != g_ActiveConfig.bForceFiltering; bool efb_scale_changed = old_efb_scale != g_ActiveConfig.iEFBScale; bool aspect_changed = old_aspect_ratio != g_ActiveConfig.iAspectRatio; - bool use_xfb_changed = old_use_xfb != g_ActiveConfig.bUseXFB; - bool use_realxfb_changed = old_use_realxfb != g_ActiveConfig.bUseRealXFB; // Update texture cache settings with any changed options. TextureCache::GetInstance()->OnConfigChanged(g_ActiveConfig); // Handle settings that can cause the target rectangle to change. - if (efb_scale_changed || aspect_changed || use_xfb_changed || use_realxfb_changed) + if (efb_scale_changed || aspect_changed) { if (CalculateTargetSize()) ResizeEFBTextures(); diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index 5a367f2bcd..2fbf240122 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -23,6 +23,7 @@ class SwapChain; class StagingTexture2D; class Texture2D; class RasterFont; +class VKTexture; class Renderer : public ::Renderer { @@ -43,8 +44,7 @@ public: void BBoxWrite(int index, u16 value) override; TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, const EFBRectangle& rc, - u64 ticks, float gamma) override; + void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override; void ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) override; @@ -72,7 +72,6 @@ private: void BeginFrame(); - void CheckForTargetResize(u32 fb_width, u32 fb_stride, u32 fb_height); void CheckForSurfaceChange(); void CheckForConfigChanges(); @@ -86,63 +85,13 @@ private: bool CompileShaders(); void DestroyShaders(); - // Transitions EFB/XFB buffers to SHADER_READ_ONLY, ready for presenting/dumping. - // If MSAA is enabled, and XFB is disabled, also resolves the EFB buffer. - void TransitionBuffersForSwap(const TargetRectangle& scaled_rect, - const XFBSourceBase* const* xfb_sources, u32 xfb_count); - - // Draw either the EFB, or specified XFB sources to the currently-bound framebuffer. - void DrawFrame(VkRenderPass render_pass, const TargetRectangle& target_rect, - const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - void DrawEFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - const TargetRectangle& scaled_efb_rect); - void DrawVirtualXFB(VkRenderPass render_pass, const TargetRectangle& target_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - void DrawRealXFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - // Draw the frame, as well as the OSD to the swap chain. - void DrawScreen(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - - // Draw the frame only to the screenshot buffer. - bool DrawFrameDump(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height, u64 ticks); - - // Sets up renderer state to permit framedumping. - // Ideally we would have EndFrameDumping be a virtual method of Renderer, but due to various - // design issues it would have to end up being called in the destructor, which won't work. - void StartFrameDumping(); - void EndFrameDumping(); - - // Fence callback so that we know when frames are ready to be written to the dump. - // This is done by clearing the fence pointer, so WriteFrameDumpFrame doesn't have to wait. - void OnFrameDumpImageReady(VkFence fence); - - // Writes the specified buffered frame to the frame dump. - // NOTE: Assumes that frame.ticks and frame.pending are valid. - void WriteFrameDumpImage(size_t index); - - // If there is a pending frame in this buffer, writes it to the frame dump. - // Ensures that the specified readback buffer meets the size requirements of the current frame. - StagingTexture2D* PrepareFrameDumpImage(u32 width, u32 height, u64 ticks); - - // Ensures all buffered frames are written to frame dump. - void FlushFrameDump(); + void DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region); // Copies/scales an image to the currently-bound framebuffer. void BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect, const TargetRectangle& src_rect, const Texture2D* src_tex); - bool ResizeFrameDumpBuffer(u32 new_width, u32 new_height); - void DestroyFrameDumpResources(); - VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE; VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE; @@ -155,22 +104,5 @@ private: // Shaders used for clear/blit. VkShaderModule m_clear_fragment_shader = VK_NULL_HANDLE; - - // Texture used for screenshot/frame dumping - std::unique_ptr m_frame_dump_render_texture; - VkFramebuffer m_frame_dump_framebuffer = VK_NULL_HANDLE; - - // Readback resources for frame dumping - static const size_t FRAME_DUMP_BUFFERED_FRAMES = 2; - struct FrameDumpImage - { - std::unique_ptr readback_texture; - VkFence fence = VK_NULL_HANDLE; - AVIDump::Frame dump_state = {}; - bool pending = false; - }; - std::array m_frame_dump_images; - size_t m_current_frame_dump_image = FRAME_DUMP_BUFFERED_FRAMES - 1; - bool m_frame_dumping_active = false; }; } diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp index 75b4a01f4c..b8ac91d06b 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -5,6 +5,7 @@ #include "VideoBackends/Vulkan/TextureConverter.h" #include +#include #include #include #include @@ -32,6 +33,14 @@ namespace Vulkan { +namespace +{ +struct EFBEncodeParams +{ + std::array position_uniform; + float y_scale; +}; +} TextureConverter::TextureConverter() { } @@ -52,6 +61,8 @@ TextureConverter::~TextureConverter() vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_r32g32_uint, nullptr); if (m_texel_buffer_view_rgba8_unorm != VK_NULL_HANDLE) vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_rgba8_unorm, nullptr); + if (m_texel_buffer_view_rgba8_uint != VK_NULL_HANDLE) + vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_rgba8_uint, nullptr); if (m_encoding_render_pass != VK_NULL_HANDLE) vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_encoding_render_pass, nullptr); @@ -150,7 +161,7 @@ TextureConverter::GetCommandBufferForTextureConversion(const TextureCache::TCach // EFB copies can be used as paletted textures as well. For these, we can't assume them to be // contain the correct data before the frame begins (when the init command buffer is executed), // so we must convert them at the appropriate time, during the drawing command buffer. - if (src_entry->IsEfbCopy()) + if (src_entry->IsCopy()) { StateTracker::GetInstance()->EndRenderPass(); StateTracker::GetInstance()->SetPendingRebind(); @@ -243,14 +254,19 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p VK_NULL_HANDLE, shader); // Uniform - int4 of left,top,native_width,scale - s32 position_uniform[4] = {src_rect.left, src_rect.top, static_cast(native_width), - scale_by_half ? 2 : 1}; - draw.SetPushConstants(position_uniform, sizeof(position_uniform)); + EFBEncodeParams encoder_params; + encoder_params.position_uniform[0] = src_rect.left; + encoder_params.position_uniform[1] = src_rect.top; + encoder_params.position_uniform[2] = static_cast(native_width); + encoder_params.position_uniform[3] = scale_by_half ? 2 : 1; + encoder_params.y_scale = params.y_scale; + draw.SetPushConstants(&encoder_params, sizeof(encoder_params)); // We also linear filtering for both box filtering and downsampling higher resolutions to 1x // TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more // complex down filtering to average all pixels and produce the correct result. - bool linear_filter = (scale_by_half && !params.depth) || g_renderer->GetEFBScale() != 1; + bool linear_filter = + (scale_by_half && !params.depth) || g_renderer->GetEFBScale() != 1 || params.y_scale > 1.0f; draw.SetPSSampler(0, src_texture, linear_filter ? g_object_cache->GetLinearSampler() : g_object_cache->GetPointSampler()); @@ -473,11 +489,22 @@ void TextureConverter::DecodeTexture(VkCommandBuffer command_buffer, // Copy/commit upload buffer. u32 texel_buffer_offset = static_cast(m_texel_buffer->GetCurrentOffset()); + + Util::BufferMemoryBarrier(g_command_buffer_mgr->GetCurrentCommandBuffer(), + m_texel_buffer->GetBuffer(), VK_ACCESS_SHADER_READ_BIT, + VK_ACCESS_HOST_WRITE_BIT, texel_buffer_offset, total_upload_size, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT); + std::memcpy(m_texel_buffer->GetCurrentHostPointer(), data, data_size); if (has_palette) std::memcpy(m_texel_buffer->GetCurrentHostPointer() + palette_offset, palette, palette_size); m_texel_buffer->CommitMemory(total_upload_size); + Util::BufferMemoryBarrier(g_command_buffer_mgr->GetCurrentCommandBuffer(), + m_texel_buffer->GetBuffer(), VK_ACCESS_HOST_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT, texel_buffer_offset, total_upload_size, + VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + // Determine uniforms. PushConstants constants = { {width, height}, @@ -499,6 +526,9 @@ void TextureConverter::DecodeTexture(VkCommandBuffer command_buffer, case TextureConversionShader::BUFFER_FORMAT_R32G32_UINT: data_view = m_texel_buffer_view_r32g32_uint; break; + case TextureConversionShader::BUFFER_FORMAT_RGBA8_UINT: + data_view = m_texel_buffer_view_rgba8_uint; + break; default: break; } @@ -550,10 +580,12 @@ bool TextureConverter::CreateTexelBuffer() m_texel_buffer_view_r16_uint = CreateTexelBufferView(VK_FORMAT_R16_UINT); m_texel_buffer_view_r32g32_uint = CreateTexelBufferView(VK_FORMAT_R32G32_UINT); m_texel_buffer_view_rgba8_unorm = CreateTexelBufferView(VK_FORMAT_R8G8B8A8_UNORM); + m_texel_buffer_view_rgba8_uint = CreateTexelBufferView(VK_FORMAT_R8G8B8A8_UINT); return m_texel_buffer_view_r8_uint != VK_NULL_HANDLE && m_texel_buffer_view_r16_uint != VK_NULL_HANDLE && m_texel_buffer_view_r32g32_uint != VK_NULL_HANDLE && - m_texel_buffer_view_rgba8_unorm != VK_NULL_HANDLE; + m_texel_buffer_view_rgba8_unorm != VK_NULL_HANDLE && + m_texel_buffer_view_rgba8_uint != VK_NULL_HANDLE; } VkBufferView TextureConverter::CreateTexelBufferView(VkFormat format) const diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.h b/Source/Core/VideoBackends/Vulkan/TextureConverter.h index 2465691901..1a62590019 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.h +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.h @@ -97,6 +97,7 @@ private: VkBufferView m_texel_buffer_view_r8_uint = VK_NULL_HANDLE; VkBufferView m_texel_buffer_view_r16_uint = VK_NULL_HANDLE; VkBufferView m_texel_buffer_view_r32g32_uint = VK_NULL_HANDLE; + VkBufferView m_texel_buffer_view_rgba8_uint = VK_NULL_HANDLE; VkBufferView m_texel_buffer_view_rgba8_unorm = VK_NULL_HANDLE; size_t m_texel_buffer_size = 0; diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp index 36292751b0..cbb6e0c063 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp @@ -113,23 +113,17 @@ void VKTexture::Bind(unsigned int stage) StateTracker::GetInstance()->SetTexture(stage, m_texture->GetView()); } -bool VKTexture::Save(const std::string& filename, unsigned int level) +std::optional VKTexture::MapFullImpl() { - _assert_(level < m_config.levels); + // No support for optimization of full copy + return MapRegionImpl(0, 0, 0, m_config.width, m_config.height); +} - // We can't dump compressed textures currently (it would mean drawing them to a RGBA8 - // framebuffer, and saving that). TextureCache does not call Save for custom textures - // anyway, so this is fine for now. - _assert_(m_config.format == AbstractTextureFormat::RGBA8); - - // Determine dimensions of image we want to save. - u32 level_width = std::max(1u, m_config.width >> level); - u32 level_height = std::max(1u, m_config.height >> level); - - // Use a temporary staging texture for the download. Certainly not optimal, - // but since we have to idle the GPU anyway it doesn't really matter. - std::unique_ptr staging_texture = StagingTexture2D::Create( - STAGING_BUFFER_TYPE_READBACK, level_width, level_height, TEXTURECACHE_TEXTURE_FORMAT); +std::optional VKTexture::MapRegionImpl(u32 level, u32 x, u32 y, + u32 width, u32 height) +{ + m_staging_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, width, height, + TEXTURECACHE_TEXTURE_FORMAT); // Transition image to transfer source, and invalidate the current state, // since we'll be executing the command buffer. @@ -138,9 +132,9 @@ bool VKTexture::Save(const std::string& filename, unsigned int level) StateTracker::GetInstance()->EndRenderPass(); // Copy to download buffer. - staging_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), - m_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, - level_width, level_height, level, 0); + m_staging_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), + m_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, x, y, width, + height, level, 0); // Restore original state of texture. m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), @@ -150,21 +144,23 @@ bool VKTexture::Save(const std::string& filename, unsigned int level) Util::ExecuteCurrentCommandsAndRestoreState(false, true); // Map the staging texture so we can copy the contents out. - if (!staging_texture->Map()) + if (!m_staging_texture->Map()) { PanicAlert("Failed to map staging texture"); - return false; + return {}; } - // Write texture out to file. - // It's okay to throw this texture away immediately, since we're done with it, and - // we blocked until the copy completed on the GPU anyway. - bool result = TextureToPng(reinterpret_cast(staging_texture->GetMapPointer()), - static_cast(staging_texture->GetRowStride()), filename, - level_width, level_height); + return AbstractTexture::RawTextureInfo{reinterpret_cast(m_staging_texture->GetMapPointer()), + static_cast(m_staging_texture->GetRowStride()), width, + height}; +} - staging_texture->Unmap(); - return result; +void VKTexture::Unmap() +{ + if (!m_staging_texture) + return; + + m_staging_texture->Unmap(); } void VKTexture::CopyTextureRectangle(const MathUtil::Rectangle& dst_rect, diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.h b/Source/Core/VideoBackends/Vulkan/VKTexture.h index 056f50c6e8..61ffae242c 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.h +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.h @@ -20,7 +20,7 @@ public: ~VKTexture(); void Bind(unsigned int stage) override; - bool Save(const std::string& filename, unsigned int level) override; + void Unmap() override; void CopyRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, @@ -47,7 +47,12 @@ private: void ScaleTextureRectangle(const MathUtil::Rectangle& dst_rect, Texture2D* src_texture, const MathUtil::Rectangle& src_rect); + std::optional MapFullImpl() override; + std::optional MapRegionImpl(u32 level, u32 x, u32 y, u32 width, + u32 height) override; + std::unique_ptr m_texture; + std::unique_ptr m_staging_texture; VkFramebuffer m_framebuffer; }; diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index e2f44b73be..9d34174e90 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -246,6 +246,8 @@ void VulkanContext::PopulateBackendInfo(VideoConfig* config) config->backend_info.bSupportsST3CTextures = false; // Dependent on features. config->backend_info.bSupportsBPTCTextures = false; // Dependent on features. config->backend_info.bSupportsReversedDepthRange = false; // No support yet due to driver bugs. + config->backend_info.bSupportsCopyToVram = true; // Assumed support. + config->backend_info.bForceCopyToRam = false; } void VulkanContext::PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list) diff --git a/Source/Core/VideoCommon/AbstractTexture.cpp b/Source/Core/VideoCommon/AbstractTexture.cpp index 18f9c72064..0e92b6f7bd 100644 --- a/Source/Core/VideoCommon/AbstractTexture.cpp +++ b/Source/Core/VideoCommon/AbstractTexture.cpp @@ -4,9 +4,12 @@ #include -#include "VideoCommon/AbstractTexture.h" +#include "Common/Assert.h" -AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c) +#include "VideoCommon/AbstractTexture.h" +#include "VideoCommon/ImageWrite.h" + +AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c), m_currently_mapped(false) { } @@ -14,7 +17,87 @@ AbstractTexture::~AbstractTexture() = default; bool AbstractTexture::Save(const std::string& filename, unsigned int level) { - return false; + // We can't dump compressed textures currently (it would mean drawing them to a RGBA8 + // framebuffer, and saving that). TextureCache does not call Save for custom textures + // anyway, so this is fine for now. + _assert_(m_config.format == AbstractTextureFormat::RGBA8); + + auto result = level == 0 ? Map() : Map(level); + + if (!result.has_value()) + { + return false; + } + + auto raw_data = result.value(); + return TextureToPng(raw_data.data, raw_data.stride, filename, raw_data.width, raw_data.height); +} + +std::optional AbstractTexture::Map() +{ + if (m_currently_mapped) + { + Unmap(); + m_currently_mapped = false; + } + auto result = MapFullImpl(); + + if (!result.has_value()) + { + m_currently_mapped = false; + return {}; + } + + m_currently_mapped = true; + return result; +} + +std::optional AbstractTexture::Map(u32 level, u32 x, u32 y, + u32 width, u32 height) +{ + _assert_(level < m_config.levels); + + u32 max_level_width = std::max(m_config.width >> level, 1u); + u32 max_level_height = std::max(m_config.height >> level, 1u); + + _assert_(width < max_level_width); + _assert_(height < max_level_height); + + auto result = MapRegionImpl(level, x, y, width, height); + + if (!result.has_value()) + { + m_currently_mapped = false; + return {}; + } + + m_currently_mapped = true; + return result; +} + +std::optional AbstractTexture::Map(u32 level) +{ + _assert_(level < m_config.levels); + + u32 level_width = std::max(m_config.width >> level, 1u); + u32 level_height = std::max(m_config.height >> level, 1u); + + return Map(level, 0, 0, level_width, level_height); +} + +void AbstractTexture::Unmap() +{ +} + +std::optional AbstractTexture::MapFullImpl() +{ + return {}; +} + +std::optional +AbstractTexture::MapRegionImpl(u32 level, u32 x, u32 y, u32 width, u32 height) +{ + return {}; } bool AbstractTexture::IsCompressedHostTextureFormat(AbstractTextureFormat format) diff --git a/Source/Core/VideoCommon/AbstractTexture.h b/Source/Core/VideoCommon/AbstractTexture.h index 94c082af70..612ca34758 100644 --- a/Source/Core/VideoCommon/AbstractTexture.h +++ b/Source/Core/VideoCommon/AbstractTexture.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include "Common/CommonTypes.h" @@ -17,7 +18,20 @@ public: explicit AbstractTexture(const TextureConfig& c); virtual ~AbstractTexture(); virtual void Bind(unsigned int stage) = 0; - virtual bool Save(const std::string& filename, unsigned int level); + bool Save(const std::string& filename, unsigned int level); + + struct RawTextureInfo + { + const u8* data; + u32 stride; + u32 width; + u32 height; + }; + + std::optional Map(); + std::optional Map(u32 level, u32 x, u32 y, u32 width, u32 height); + std::optional Map(u32 level); + virtual void Unmap(); virtual void CopyRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, @@ -31,5 +45,10 @@ public: const TextureConfig& GetConfig() const; protected: + virtual std::optional MapFullImpl(); + virtual std::optional MapRegionImpl(u32 level, u32 x, u32 y, u32 width, + u32 height); + bool m_currently_mapped = false; + const TextureConfig m_config; }; diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index 5605284092..5bf53832c3 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -12,8 +12,11 @@ #include "Common/StringUtil.h" #include "Common/Thread.h" #include "Core/ConfigManager.h" +#include "Core/CoreTiming.h" +#include "Core/FifoPlayer/FifoPlayer.h" #include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/Memmap.h" +#include "Core/HW/VideoInterface.h" #include "VideoCommon/BPFunctions.h" #include "VideoCommon/BPMemory.h" @@ -230,7 +233,7 @@ static void BPWritten(const BPCmd& bp) bool is_depth_copy = bpmem.zcontrol.pixel_format == PEControl::Z24; g_texture_cache->CopyRenderTargetToTexture(destAddr, PE_copy.tp_realFormat(), destStride, is_depth_copy, srcRect, !!PE_copy.intensity_fmt, - !!PE_copy.half_scale); + !!PE_copy.half_scale, 1.0f, 1.0f); } else { @@ -250,17 +253,33 @@ static void BPWritten(const BPCmd& bp) float num_xfb_lines = 1.0f + bpmem.copyTexSrcWH.y * yScale; u32 height = static_cast(num_xfb_lines); - if (height > MAX_XFB_HEIGHT) - { - INFO_LOG(VIDEO, "Tried to scale EFB to too many XFB lines: %d (%f)", height, num_xfb_lines); - height = MAX_XFB_HEIGHT; - } DEBUG_LOG(VIDEO, "RenderToXFB: destAddr: %08x | srcRect {%d %d %d %d} | fbWidth: %u | " "fbStride: %u | fbHeight: %u", destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, bpmem.copyTexSrcWH.x + 1, destStride, height); + + bool is_depth_copy = bpmem.zcontrol.pixel_format == PEControl::Z24; + g_texture_cache->CopyRenderTargetToTexture(destAddr, EFBCopyFormat::XFB, destStride, + is_depth_copy, srcRect, false, false, yScale, + s_gammaLUT[PE_copy.gamma]); + + // This stays in to signal end of a "frame" g_renderer->RenderToXFB(destAddr, srcRect, destStride, height, s_gammaLUT[PE_copy.gamma]); + + if (g_ActiveConfig.bImmediateXFB) + { + // below div two to convert from bytes to pixels - it expects width, not stride + g_renderer->Swap(destAddr, destStride / 2, destStride / 2, height, srcRect, + CoreTiming::GetTicks()); + } + else + { + if (FifoPlayer::GetInstance().IsRunningWithFakeVideoInterfaceUpdates()) + { + VideoInterface::FakeVIUpdate(destAddr, srcRect.GetWidth(), height); + } + } } // Clear the rectangular region after copying it. diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.cpp b/Source/Core/VideoCommon/FramebufferManagerBase.cpp index dd2cc88735..1df2960b1a 100644 --- a/Source/Core/VideoCommon/FramebufferManagerBase.cpp +++ b/Source/Core/VideoCommon/FramebufferManagerBase.cpp @@ -14,252 +14,6 @@ std::unique_ptr g_framebuffer_manager; -std::unique_ptr - FramebufferManagerBase::m_realXFBSource; // Only used in Real XFB mode -FramebufferManagerBase::VirtualXFBListType - FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode -std::array - FramebufferManagerBase::m_overlappingXFBArray; - -unsigned int FramebufferManagerBase::s_last_xfb_width = 1; -unsigned int FramebufferManagerBase::s_last_xfb_height = 1; - unsigned int FramebufferManagerBase::m_EFBLayers = 1; -FramebufferManagerBase::FramebufferManagerBase() -{ - // Can't hurt - m_overlappingXFBArray.fill(nullptr); -} - -FramebufferManagerBase::~FramebufferManagerBase() -{ - // Necessary, as these are static members - // (they really shouldn't be and should be refactored at some point). - m_virtualXFBList.clear(); - m_realXFBSource.reset(); -} - -const XFBSourceBase* const* FramebufferManagerBase::GetXFBSource(u32 xfbAddr, u32 fbWidth, - u32 fbHeight, u32* xfbCountP) -{ - if (!g_ActiveConfig.bUseXFB) - return nullptr; - - if (g_ActiveConfig.bUseRealXFB) - return GetRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCountP); - else - return GetVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCountP); -} - -const XFBSourceBase* const* FramebufferManagerBase::GetRealXFBSource(u32 xfbAddr, u32 fbWidth, - u32 fbHeight, u32* xfbCountP) -{ - *xfbCountP = 1; - - // recreate if needed - if (m_realXFBSource && - (m_realXFBSource->texWidth != fbWidth || m_realXFBSource->texHeight != fbHeight)) - m_realXFBSource.reset(); - - if (!m_realXFBSource && g_framebuffer_manager) - m_realXFBSource = g_framebuffer_manager->CreateXFBSource(fbWidth, fbHeight, 1); - - if (!m_realXFBSource) - return nullptr; - - m_realXFBSource->srcAddr = xfbAddr; - - m_realXFBSource->srcWidth = MAX_XFB_WIDTH; - m_realXFBSource->srcHeight = MAX_XFB_HEIGHT; - - m_realXFBSource->texWidth = fbWidth; - m_realXFBSource->texHeight = fbHeight; - - m_realXFBSource->sourceRc.left = 0; - m_realXFBSource->sourceRc.top = 0; - m_realXFBSource->sourceRc.right = fbWidth; - m_realXFBSource->sourceRc.bottom = fbHeight; - - // Decode YUYV data from GameCube RAM - m_realXFBSource->DecodeToTexture(xfbAddr, fbWidth, fbHeight); - - m_overlappingXFBArray[0] = m_realXFBSource.get(); - return &m_overlappingXFBArray[0]; -} - -const XFBSourceBase* const* -FramebufferManagerBase::GetVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32* xfbCountP) -{ - u32 xfbCount = 0; - - if (m_virtualXFBList.empty()) // no Virtual XFBs available - return nullptr; - - u32 srcLower = xfbAddr; - u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight; - - VirtualXFBListType::reverse_iterator it = m_virtualXFBList.rbegin(), - vlend = m_virtualXFBList.rend(); - for (; it != vlend; ++it) - { - VirtualXFB* vxfb = &*it; - - u32 dstLower = vxfb->xfbAddr; - u32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; - - if (AddressRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) - { - m_overlappingXFBArray[xfbCount] = vxfb->xfbSource.get(); - ++xfbCount; - } - } - - *xfbCountP = xfbCount; - return &m_overlappingXFBArray[0]; -} - -void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, - const EFBRectangle& sourceRc, float Gamma) -{ - if (g_ActiveConfig.bUseRealXFB) - { - if (g_framebuffer_manager) - g_framebuffer_manager->CopyToRealXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); - } - else - { - CopyToVirtualXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); - } -} - -void FramebufferManagerBase::CopyToVirtualXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, - const EFBRectangle& sourceRc, float Gamma) -{ - if (!g_framebuffer_manager) - return; - - VirtualXFBListType::iterator vxfb = FindVirtualXFB(xfbAddr, sourceRc.GetWidth(), fbHeight); - - if (m_virtualXFBList.end() == vxfb) - { - if (m_virtualXFBList.size() < MAX_VIRTUAL_XFB) - { - // create a new Virtual XFB and place it at the front of the list - m_virtualXFBList.emplace_front(); - vxfb = m_virtualXFBList.begin(); - } - else - { - // Replace the last virtual XFB - --vxfb; - } - } - // else // replace existing virtual XFB - - // move this Virtual XFB to the front of the list. - if (m_virtualXFBList.begin() != vxfb) - m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, vxfb); - - u32 target_width, target_height; - std::tie(target_width, target_height) = g_framebuffer_manager->GetTargetSize(); - - // recreate if needed - if (vxfb->xfbSource && - (vxfb->xfbSource->texWidth != target_width || vxfb->xfbSource->texHeight != target_height)) - vxfb->xfbSource.reset(); - - if (!vxfb->xfbSource) - { - vxfb->xfbSource = - g_framebuffer_manager->CreateXFBSource(target_width, target_height, m_EFBLayers); - if (!vxfb->xfbSource) - return; - - vxfb->xfbSource->texWidth = target_width; - vxfb->xfbSource->texHeight = target_height; - } - - vxfb->xfbSource->srcAddr = vxfb->xfbAddr = xfbAddr; - vxfb->xfbSource->srcWidth = vxfb->xfbWidth = sourceRc.GetWidth(); - vxfb->xfbSource->srcHeight = vxfb->xfbHeight = fbHeight; - - vxfb->xfbSource->sourceRc = g_renderer->ConvertEFBRectangle(sourceRc); - - // keep stale XFB data from being used - ReplaceVirtualXFB(); - - // Copy EFB data to XFB and restore render target again - vxfb->xfbSource->CopyEFB(Gamma); -} - -FramebufferManagerBase::VirtualXFBListType::iterator -FramebufferManagerBase::FindVirtualXFB(u32 xfbAddr, u32 width, u32 height) -{ - const u32 srcLower = xfbAddr; - const u32 srcUpper = xfbAddr + 2 * width * height; - - return std::find_if(m_virtualXFBList.begin(), m_virtualXFBList.end(), - [srcLower, srcUpper](const VirtualXFB& xfb) { - const u32 dstLower = xfb.xfbAddr; - const u32 dstUpper = xfb.xfbAddr + 2 * xfb.xfbWidth * xfb.xfbHeight; - - return dstLower >= srcLower && dstUpper <= srcUpper; - }); -} - -void FramebufferManagerBase::ReplaceVirtualXFB() -{ - VirtualXFBListType::iterator it = m_virtualXFBList.begin(); - - const s32 srcLower = it->xfbAddr; - const s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; - const s32 lineSize = 2 * it->xfbWidth; - - ++it; - - for (; it != m_virtualXFBList.end(); ++it) - { - s32 dstLower = it->xfbAddr; - s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; - - if (dstLower >= srcLower && dstUpper <= srcUpper) - { - // Invalidate the data - it->xfbAddr = 0; - it->xfbHeight = 0; - it->xfbWidth = 0; - } - else if (AddressRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) - { - s32 upperOverlap = (srcUpper - dstLower) / lineSize; - s32 lowerOverlap = (dstUpper - srcLower) / lineSize; - - if (upperOverlap > 0 && lowerOverlap < 0) - { - it->xfbAddr += lineSize * upperOverlap; - it->xfbHeight -= upperOverlap; - } - else if (lowerOverlap > 0) - { - it->xfbHeight -= lowerOverlap; - } - } - } -} - -int FramebufferManagerBase::ScaleToVirtualXfbWidth(int x, const TargetRectangle& target_rectangle) -{ - if (g_ActiveConfig.RealXFBEnabled()) - return x; - - return x * target_rectangle.GetWidth() / s_last_xfb_width; -} - -int FramebufferManagerBase::ScaleToVirtualXfbHeight(int y, const TargetRectangle& target_rectangle) -{ - if (g_ActiveConfig.RealXFBEnabled()) - return y; - - return y * target_rectangle.GetHeight() / s_last_xfb_height; -} +FramebufferManagerBase::~FramebufferManagerBase() = default; diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.h b/Source/Core/VideoCommon/FramebufferManagerBase.h index c780a3fa21..5e645dc7f7 100644 --- a/Source/Core/VideoCommon/FramebufferManagerBase.h +++ b/Source/Core/VideoCommon/FramebufferManagerBase.h @@ -17,94 +17,14 @@ inline bool AddressRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) return !((aLower >= bUpper) || (bLower >= aUpper)); } -struct XFBSourceBase -{ - virtual ~XFBSourceBase() {} - virtual void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) = 0; - - virtual void CopyEFB(float Gamma) = 0; - - u32 srcAddr; - u32 srcWidth; - u32 srcHeight; - - unsigned int texWidth; - unsigned int texHeight; - - // TODO: only used by OGL - TargetRectangle sourceRc; -}; - class FramebufferManagerBase { public: - enum - { - // There may be multiple XFBs in GameCube RAM. This is the maximum number to - // virtualize. - MAX_VIRTUAL_XFB = 8 - }; - - FramebufferManagerBase(); virtual ~FramebufferManagerBase(); - static void CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma); - static const XFBSourceBase* const* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, - u32* xfbCount); - - static void SetLastXfbWidth(unsigned int width) { s_last_xfb_width = width; } - static void SetLastXfbHeight(unsigned int height) { s_last_xfb_height = height; } - static unsigned int LastXfbWidth() { return s_last_xfb_width; } - static unsigned int LastXfbHeight() { return s_last_xfb_height; } - static int ScaleToVirtualXfbWidth(int x, const TargetRectangle& target_rectangle); - static int ScaleToVirtualXfbHeight(int y, const TargetRectangle& target_rectangle); - static unsigned int GetEFBLayers() { return m_EFBLayers; } - virtual std::pair GetTargetSize() const = 0; - protected: - struct VirtualXFB - { - VirtualXFB() {} - // Address and size in GameCube RAM - u32 xfbAddr = 0; - u32 xfbWidth = 0; - u32 xfbHeight = 0; - - std::unique_ptr xfbSource; - }; - - typedef std::list VirtualXFBListType; - static unsigned int m_EFBLayers; - -private: - virtual std::unique_ptr - CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) = 0; - - static VirtualXFBListType::iterator FindVirtualXFB(u32 xfbAddr, u32 width, u32 height); - - static void ReplaceVirtualXFB(); - - // TODO: merge these virtual funcs, they are nearly all the same - virtual void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma = 1.0f) = 0; - static void CopyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma = 1.0f); - - static const XFBSourceBase* const* GetRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, - u32* xfbCount); - static const XFBSourceBase* const* GetVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, - u32* xfbCount); - - static std::unique_ptr m_realXFBSource; // Only used in Real XFB mode - static VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode - - static std::array m_overlappingXFBArray; - - static unsigned int s_last_xfb_width; - static unsigned int s_last_xfb_height; }; extern std::unique_ptr g_framebuffer_manager; diff --git a/Source/Core/VideoCommon/MainBase.cpp b/Source/Core/VideoCommon/MainBase.cpp index d442e7f0b8..280fed683d 100644 --- a/Source/Core/VideoCommon/MainBase.cpp +++ b/Source/Core/VideoCommon/MainBase.cpp @@ -45,11 +45,20 @@ void VideoBackendBase::Video_ExitLoop() s_FifoShuttingDown.Set(); } +void VideoBackendBase::Video_CleanupShared() +{ + // First stop any framedumping, which might need to dump the last xfb frame. This process + // can require additional graphics sub-systems so it needs to be done first + g_renderer->ExitFramedumping(); + + Video_Cleanup(); +} + // Run from the CPU thread (from VideoInterface.cpp) void VideoBackendBase::Video_BeginField(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, u64 ticks) { - if (m_initialized && g_ActiveConfig.bUseXFB && g_renderer) + if (m_initialized && g_renderer && !g_ActiveConfig.bImmediateXFB) { Fifo::SyncGPU(Fifo::SyncGPUReason::Swap); diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 63e3f5f5ed..0db81bb885 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -37,13 +37,13 @@ #include "Core/Config/SYSCONFSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/CoreTiming.h" #include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/VideoInterface.h" #include "Core/Host.h" #include "Core/Movie.h" #include "VideoCommon/AVIDump.h" +#include "VideoCommon/AbstractTexture.h" #include "VideoCommon/BPMemory.h" #include "VideoCommon/CPMemory.h" #include "VideoCommon/CommandProcessor.h" @@ -84,9 +84,6 @@ static float AspectToWidescreen(float aspect) Renderer::Renderer(int backbuffer_width, int backbuffer_height) : m_backbuffer_width(backbuffer_width), m_backbuffer_height(backbuffer_height) { - FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); - FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); - UpdateActiveConfig(); UpdateDrawRectangle(); CalculateTargetSize(); @@ -100,11 +97,15 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height) m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits; } -Renderer::~Renderer() +Renderer::~Renderer() = default; + +void Renderer::ExitFramedumping() { ShutdownFrameDumping(); if (m_frame_dump_thread.joinable()) m_frame_dump_thread.join(); + + m_dump_texture.reset(); } void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStride, u32 fbHeight, @@ -114,21 +115,6 @@ void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStri if (!fbStride || !fbHeight) return; - - m_xfb_written = true; - - if (g_ActiveConfig.bUseXFB) - { - FramebufferManagerBase::CopyToXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); - } - else - { - // The timing is not predictable here. So try to use the XFB path to dump frames. - u64 ticks = CoreTiming::GetTicks(); - - // below div two to convert from bytes to pixels - it expects width, not stride - Swap(xfbAddr, fbStride / 2, fbStride / 2, fbHeight, sourceRc, ticks, Gamma); - } } unsigned int Renderer::GetEFBScale() const @@ -167,8 +153,8 @@ bool Renderer::CalculateTargetSize() if (g_ActiveConfig.iEFBScale == EFB_SCALE_AUTO_INTEGRAL) { // Set a scale based on the window size - int width = FramebufferManagerBase::ScaleToVirtualXfbWidth(EFB_WIDTH, m_target_rectangle); - int height = FramebufferManagerBase::ScaleToVirtualXfbHeight(EFB_HEIGHT, m_target_rectangle); + int width = EFB_WIDTH * m_target_rectangle.GetWidth() / m_last_xfb_width; + int height = EFB_HEIGHT * m_target_rectangle.GetWidth() / m_last_xfb_height; m_efb_scale = std::max((width - 1) / EFB_WIDTH + 1, (height - 1) / EFB_HEIGHT + 1); } else @@ -342,6 +328,7 @@ void Renderer::DrawDebugText() } const char* const efbcopy_text = g_ActiveConfig.bSkipEFBCopyToRam ? "to Texture" : "to RAM"; + const char* const xfbcopy_text = g_ActiveConfig.bSkipXFBCopyToRam ? "to Texture" : "to RAM"; // The rows const std::string lines[] = { @@ -353,6 +340,8 @@ void Renderer::DrawDebugText() "Speed Limit: Unlimited" : StringFromFormat("Speed Limit: %li%%", std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f)), + std::string("Copy XFB: ") + xfbcopy_text + + (g_ActiveConfig.bImmediateXFB ? " (Immediate)" : ""), }; enum @@ -425,36 +414,6 @@ std::tuple Renderer::ScaleToDisplayAspectRatio(const int width, return std::make_tuple(scaled_width, scaled_height); } -TargetRectangle Renderer::CalculateFrameDumpDrawRectangle() const -{ - // No point including any borders in the frame dump image, since they'd have to be cropped anyway. - TargetRectangle rc; - rc.left = 0; - rc.top = 0; - - // If full-resolution frame dumping is disabled, just use the window draw rectangle. - // Also do this if RealXFB is enabled, since the image has been downscaled for the XFB copy - // anyway, and there's no point writing an upscaled frame with no filtering. - if (!g_ActiveConfig.bInternalResolutionFrameDumps || g_ActiveConfig.RealXFBEnabled()) - { - // But still remove the borders, since the caller expects this. - rc.right = m_target_rectangle.GetWidth(); - rc.bottom = m_target_rectangle.GetHeight(); - return rc; - } - - // Grab the dimensions of the EFB textures, we scale either of these depending on the ratio. - u32 efb_width, efb_height; - std::tie(efb_width, efb_height) = g_framebuffer_manager->GetTargetSize(); - - float draw_width, draw_height; - std::tie(draw_width, draw_height) = ScaleToDisplayAspectRatio(efb_width, efb_height); - - rc.right = static_cast(std::ceil(draw_width)); - rc.bottom = static_cast(std::ceil(draw_height)); - return rc; -} - void Renderer::UpdateDrawRectangle() { // The rendering window size @@ -564,13 +523,26 @@ void Renderer::UpdateDrawRectangle() void Renderer::SetWindowSize(int width, int height) { - width = std::max(width, 1); - height = std::max(height, 1); - // Scale the window size by the EFB scale. if (g_ActiveConfig.iEFBScale != EFB_SCALE_AUTO_INTEGRAL) std::tie(width, height) = CalculateTargetScale(width, height); + std::tie(width, height) = CalculateOutputDimensions(width, height); + + // Track the last values of width/height to avoid sending a window resize event every frame. + if (width != m_last_window_request_width || height != m_last_window_request_height) + { + m_last_window_request_width = width; + m_last_window_request_height = height; + Host_RequestRenderWindowSize(width, height); + } +} + +std::tuple Renderer::CalculateOutputDimensions(int width, int height) +{ + width = std::max(width, 1); + height = std::max(height, 1); + float scaled_width, scaled_height; std::tie(scaled_width, scaled_height) = ScaleToDisplayAspectRatio(width, height); @@ -602,13 +574,7 @@ void Renderer::SetWindowSize(int width, int height) width -= width % 4; height -= height % 4; - // Track the last values of width/height to avoid sending a window resize event every frame. - if (width != m_last_window_request_width || height != m_last_window_request_height) - { - m_last_window_request_width = width; - m_last_window_request_height = height; - Host_RequestRenderWindowSize(width, height); - } + return std::make_tuple(width, height); } void Renderer::CheckFifoRecording() @@ -645,7 +611,7 @@ void Renderer::RecordVideoMemory() } void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, - u64 ticks, float Gamma) + u64 ticks) { // Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode. if (!SConfig::GetInstance().bWii) @@ -663,11 +629,49 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const m_aspect_wide = flush_count_anamorphic > 0.75 * flush_total; } - // TODO: merge more generic parts into VideoCommon - SwapImpl(xfbAddr, fbWidth, fbStride, fbHeight, rc, ticks, Gamma); + if (IsFrameDumping() && m_last_xfb_texture) + { + FinishFrameData(); + } + else + { + ShutdownFrameDumping(); + } - if (m_xfb_written) - m_fps_counter.Update(); + bool update_frame_count = false; + if (xfbAddr && fbWidth && fbStride && fbHeight) + { + constexpr int force_safe_texture_cache_hash = 0; + // Get the current XFB from texture cache + auto* xfb_entry = g_texture_cache->GetXFBTexture( + xfbAddr, fbStride, fbHeight, TextureFormat::XFB, force_safe_texture_cache_hash); + + if (xfb_entry && xfb_entry->id != m_last_xfb_id) + { + m_last_xfb_texture = xfb_entry->texture.get(); + m_last_xfb_id = xfb_entry->id; + m_last_xfb_ticks = ticks; + + auto xfb_rect = xfb_entry->texture->GetConfig().GetRect(); + xfb_rect.right -= EFBToScaledX(fbStride - fbWidth); + + m_last_xfb_region = xfb_rect; + + // TODO: merge more generic parts into VideoCommon + g_renderer->SwapImpl(xfb_entry->texture.get(), xfb_rect, ticks, xfb_entry->gamma); + + m_fps_counter.Update(); + update_frame_count = true; + if (IsFrameDumping()) + { + DoDumpFrame(); + } + } + + // Update our last xfb values + m_last_xfb_width = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; + m_last_xfb_height = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; + } frameCount++; GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true); @@ -677,9 +681,7 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const // New frame stats.ResetFrame(); - Core::Callback_VideoCopiedToXFB(m_xfb_written || - (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)); - m_xfb_written = false; + Core::Callback_VideoCopiedToXFB(update_frame_count); } bool Renderer::IsFrameDumping() @@ -690,10 +692,41 @@ bool Renderer::IsFrameDumping() if (SConfig::GetInstance().m_DumpFrames) return true; - ShutdownFrameDumping(); return false; } +void Renderer::DoDumpFrame() +{ + UpdateFrameDumpTexture(); + + auto result = m_dump_texture->Map(); + if (result.has_value()) + { + auto raw_data = result.value(); + DumpFrameData(raw_data.data, raw_data.width, raw_data.height, raw_data.stride, + AVIDump::FetchState(m_last_xfb_ticks)); + } +} + +void Renderer::UpdateFrameDumpTexture() +{ + int target_width, target_height; + std::tie(target_width, target_height) = CalculateOutputDimensions( + m_last_xfb_texture->GetConfig().width, m_last_xfb_texture->GetConfig().height); + if (m_dump_texture == nullptr || + m_dump_texture->GetConfig().width != static_cast(target_width) || + m_dump_texture->GetConfig().height != static_cast(target_height)) + { + TextureConfig config; + config.width = target_width; + config.height = target_height; + config.rendertarget = true; + m_dump_texture = g_texture_cache->CreateTexture(config); + } + m_dump_texture->CopyRectangleFromTexture(m_last_xfb_texture, m_last_xfb_region, + EFBRectangle{0, 0, target_width, target_height}); +} + void Renderer::ShutdownFrameDumping() { if (!m_frame_dump_thread_running.IsSet()) @@ -704,12 +737,9 @@ void Renderer::ShutdownFrameDumping() m_frame_dump_start.Set(); } -void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state, - bool swap_upside_down) +void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state) { - FinishFrameData(); - - m_frame_dump_config = FrameDumpConfig{data, w, h, stride, swap_upside_down, state}; + m_frame_dump_config = FrameDumpConfig{m_last_xfb_texture, data, w, h, stride, state}; if (!m_frame_dump_thread_running.IsSet()) { @@ -730,6 +760,7 @@ void Renderer::FinishFrameData() m_frame_dump_done.Wait(); m_frame_dump_frame_running = false; + m_frame_dump_config.texture->Unmap(); } void Renderer::RunFrameDumps() @@ -756,12 +787,6 @@ void Renderer::RunFrameDumps() auto config = m_frame_dump_config; - if (config.upside_down) - { - config.data = config.data + (config.height - 1) * config.stride; - config.stride = -config.stride; - } - // Save screenshot if (m_screenshot_request.TestAndClear()) { diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 30f16c35a0..b622372b90 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -32,6 +32,8 @@ #include "VideoCommon/RenderState.h" #include "VideoCommon/VideoCommon.h" +class AbstractRawTexture; +class AbstractTexture; class PostProcessingShaderImplementation; enum class EFBAccessType; @@ -94,7 +96,6 @@ public: float CalculateDrawAspectRatio() const; std::tuple ScaleToDisplayAspectRatio(int width, int height) const; - TargetRectangle CalculateFrameDumpDrawRectangle() const; void UpdateDrawRectangle(); // Use this to convert a single target rectangle to two stereo rectangles @@ -130,10 +131,10 @@ public: virtual void BBoxWrite(int index, u16 value) = 0; // Finish up the current frame, print some stats - void Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, u64 ticks, - float Gamma = 1.0f); - virtual void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, - const EFBRectangle& rc, u64 ticks, float Gamma = 1.0f) = 0; + void Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, + u64 ticks); + virtual void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, + float Gamma = 1.0f) = 0; PEControl::PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; } void StorePixelFormat(PEControl::PixelFormat new_format) { m_prev_efb_format = new_format; } @@ -143,6 +144,8 @@ public: virtual void ChangeSurface(void* new_surface_handle) {} bool UseVertexDepthRange() const; + void ExitFramedumping(); + protected: std::tuple CalculateTargetScale(int x, int y) const; bool CalculateTargetSize(); @@ -152,11 +155,6 @@ protected: void CheckFifoRecording(); void RecordVideoMemory(); - bool IsFrameDumping(); - void DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state, - bool swap_upside_down = false); - void FinishFrameData(); - Common::Flag m_screenshot_request; Common::Event m_screenshot_completed; std::mutex m_screenshot_lock; @@ -171,7 +169,6 @@ protected: int m_backbuffer_width = 0; int m_backbuffer_height = 0; TargetRectangle m_target_rectangle = {}; - bool m_xfb_written = false; FPSCounter m_fps_counter; @@ -186,8 +183,11 @@ protected: u32 m_last_host_config_bits = 0; private: + void DoDumpFrame(); void RunFrameDumps(); void ShutdownFrameDumping(); + std::tuple CalculateOutputDimensions(int width, int height); + void UpdateFrameDumpTexture(); PEControl::PixelFormat m_prev_efb_format = PEControl::INVALID_FMT; unsigned int m_efb_scale = 1; @@ -205,14 +205,25 @@ private: bool m_frame_dump_frame_running = false; struct FrameDumpConfig { + AbstractTexture* texture; const u8* data; int width; int height; int stride; - bool upside_down; AVIDump::Frame state; } m_frame_dump_config; + AbstractTexture* m_last_xfb_texture = nullptr; + u64 m_last_xfb_id = std::numeric_limits::max(); + u64 m_last_xfb_ticks = 0; + EFBRectangle m_last_xfb_region; + + std::unique_ptr m_dump_texture; + + // Note: Only used for auto-ir + u32 m_last_xfb_width = MAX_XFB_WIDTH; + u32 m_last_xfb_height = MAX_XFB_HEIGHT; + // NOTE: The methods below are called on the framedumping thread. bool StartFrameDumpToAVI(const FrameDumpConfig& config); void DumpFrameToAVI(const FrameDumpConfig& config); @@ -220,6 +231,10 @@ private: std::string GetFrameDumpNextImageFileName() const; bool StartFrameDumpToImage(const FrameDumpConfig& config); void DumpFrameToImage(const FrameDumpConfig& config); + + bool IsFrameDumping(); + void DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state); + void FinishFrameData(); }; extern std::unique_ptr g_renderer; diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 0c0d0e4e36..07b6609282 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -158,7 +158,7 @@ void TextureCacheBase::Cleanup(int _frameCount) } else if (_frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) { - if (iter->second->IsEfbCopy()) + if (iter->second->IsCopy()) { // Only remove EFB copies when they wouldn't be used anymore(changed hash), because EFB // copies living on the @@ -238,11 +238,13 @@ TextureCacheBase::ApplyPaletteToEntry(TCacheEntry* entry, u8* palette, TLUTForma if (!decoded_entry) return nullptr; - decoded_entry->SetGeneralParameters(entry->addr, entry->size_in_bytes, entry->format); + decoded_entry->SetGeneralParameters(entry->addr, entry->size_in_bytes, entry->format, + entry->should_force_safe_hashing); decoded_entry->SetDimensions(entry->native_width, entry->native_height, 1); decoded_entry->SetHashes(entry->base_hash, entry->hash); decoded_entry->frameCount = FRAMECOUNT_INVALID; - decoded_entry->is_efb_copy = false; + decoded_entry->should_force_safe_hashing = false; + decoded_entry->SetNotCopy(); decoded_entry->may_have_overlapping_textures = entry->may_have_overlapping_textures; ConvertTexture(decoded_entry, entry, palette, tlutfmt); @@ -306,7 +308,7 @@ TextureCacheBase::DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* pale // EFB copies are excluded from these updates, until there's an example where a game would // benefit from updating. This would require more work to be done. - if (entry_to_update->IsEfbCopy()) + if (entry_to_update->IsCopy()) return entry_to_update; u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format.texfmt); @@ -320,7 +322,7 @@ TextureCacheBase::DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* pale while (iter.first != iter.second) { TCacheEntry* entry = iter.first->second; - if (entry != entry_to_update && entry->IsEfbCopy() && !entry->tmem_only && + if (entry != entry_to_update && entry->IsCopy() && !entry->tmem_only && entry->references.count(entry_to_update) == 0 && entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes) && entry->memory_stride == numBlocksX * block_size) @@ -462,20 +464,6 @@ static u32 CalculateLevelSize(u32 level_0_size, u32 level) return std::max(level_0_size >> level, 1u); } -// Used by TextureCacheBase::Load -TextureCacheBase::TCacheEntry* TextureCacheBase::ReturnEntry(unsigned int stage, TCacheEntry* entry) -{ - entry->frameCount = FRAMECOUNT_INVALID; - bound_textures[stage] = entry; - - GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true); - - // We need to keep track of invalided textures until they have actually been replaced or re-loaded - valid_bind_points.set(stage); - - return entry; -} - void TextureCacheBase::BindTextures() { for (size_t i = 0; i < bound_textures.size(); ++i) @@ -625,7 +613,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) // if this stage was not invalidated by changes to texture registers, keep the current texture if (IsValidBindPoint(stage) && bound_textures[stage]) { - return ReturnEntry(stage, bound_textures[stage]); + return bound_textures[stage]; } const FourTexUnits& tex = bpmem.tex[stage >> 2]; @@ -639,7 +627,34 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) const bool use_mipmaps = SamplerCommon::AreBpTexMode0MipmapsEnabled(tex.texMode0[id]); u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1; const bool from_tmem = tex.texImage1[id].image_type != 0; + const u32 tmem_address_even = from_tmem ? tex.texImage1[id].tmem_even * TMEM_LINE_SIZE : 0; + const u32 tmem_address_odd = from_tmem ? tex.texImage2[id].tmem_odd * TMEM_LINE_SIZE : 0; + auto entry = GetTexture(address, width, height, texformat, + g_ActiveConfig.iSafeTextureCache_ColorSamples, tlutaddr, tlutfmt, + use_mipmaps, tex_levels, from_tmem, tmem_address_even, tmem_address_odd); + + if (!entry) + return nullptr; + + entry->frameCount = FRAMECOUNT_INVALID; + bound_textures[stage] = entry; + + GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true); + + // We need to keep track of invalided textures until they have actually been replaced or + // re-loaded + valid_bind_points.set(stage); + + return entry; +} + +TextureCacheBase::TCacheEntry* +TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFormat texformat, + const int textureCacheSafetyColorSampleSize, u32 tlutaddr, + TLUTFormat tlutfmt, bool use_mipmaps, u32 tex_levels, bool from_tmem, + u32 tmem_address_even, u32 tmem_address_odd) +{ // TexelSizeInNibbles(format) * width * height / 16; const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat); const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat); @@ -683,9 +698,12 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat); } + // TODO: the texture cache lookup is based on address, but a texture from tmem has no reason + // to have a unique and valid address. This could result in a regular texture and a tmem + // texture aliasing onto the same texture cache entry. const u8* src_data; if (from_tmem) - src_data = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE]; + src_data = &texMem[tmem_address_even]; else src_data = Memory::GetPointer(address); @@ -704,13 +722,13 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) // TODO: This doesn't hash GB tiles for preloaded RGBA8 textures (instead, it's hashing more data // from the low tmem bank than it should) - base_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); + base_hash = GetHash64(src_data, texture_size, textureCacheSafetyColorSampleSize); u32 palette_size = 0; if (isPaletteTexture) { palette_size = TexDecoder_GetPaletteSize(texformat); - full_hash = base_hash ^ GetHash64(&texMem[tlutaddr], palette_size, - g_ActiveConfig.iSafeTextureCache_ColorSamples); + full_hash = + base_hash ^ GetHash64(&texMem[tlutaddr], palette_size, textureCacheSafetyColorSampleSize); } else { @@ -789,7 +807,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) // texture formats. I'm not sure what effect checking width/height/levels // would have. if (!isPaletteTexture || !g_Config.backend_info.bSupportsPaletteConversion) - return ReturnEntry(stage, entry); + return entry; // Note that we found an unconverted EFB copy, then continue. We'll // perform the conversion later. Currently, we only convert EFB copies to @@ -816,7 +834,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) { entry = DoPartialTextureUpdates(iter->second, &texMem[tlutaddr], tlutfmt); - return ReturnEntry(stage, entry); + return entry; } } @@ -841,7 +859,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) if (decoded_entry) { - return ReturnEntry(stage, decoded_entry); + return decoded_entry; } } @@ -851,9 +869,8 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) // textures cause unnecessary slowdowns // Example: Tales of Symphonia (GC) uses over 500 small textures in menus, but only around 70 // different ones - if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || - std::max(texture_size, palette_size) <= - (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) + if (textureCacheSafetyColorSampleSize == 0 || + std::max(texture_size, palette_size) <= (u32)textureCacheSafetyColorSampleSize * 8) { auto hash_range = textures_by_hash.equal_range(full_hash); TexHashCache::iterator hash_iter = hash_range.first; @@ -866,7 +883,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) { entry = DoPartialTextureUpdates(hash_iter->second, &texMem[tlutaddr], tlutfmt); - return ReturnEntry(stage, entry); + return entry; } ++hash_iter; } @@ -936,69 +953,70 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) // Initialized to null because only software loading uses this buffer u8* dst_buffer = nullptr; - if (!hires_tex && decode_on_gpu) + if (!hires_tex) { - u32 row_stride = bytes_per_block * (expandedWidth / bsw); - g_texture_cache->DecodeTextureOnGPU(entry, 0, src_data, texture_size, texformat, width, height, - expandedWidth, expandedHeight, row_stride, tlut, tlutfmt); - } - else if (!hires_tex) - { - size_t decoded_texture_size = expandedWidth * sizeof(u32) * expandedHeight; - - // Allocate memory for all levels at once - size_t total_texture_size = decoded_texture_size; - - // For the downsample, we need 2 buffers; 1 is 1/4 of the original texture, the other 1/16 - size_t mip_downsample_buffer_size = decoded_texture_size * 5 / 16; - - size_t prev_level_size = decoded_texture_size; - for (u32 i = 1; i < tex_levels; ++i) + if (decode_on_gpu) { - prev_level_size /= 4; - total_texture_size += prev_level_size; - } - - // Add space for the downsampling at the end - total_texture_size += mip_downsample_buffer_size; - - CheckTempSize(total_texture_size); - dst_buffer = temp; - - if (!(texformat == TextureFormat::RGBA8 && from_tmem)) - { - TexDecoder_Decode(dst_buffer, src_data, expandedWidth, expandedHeight, texformat, tlut, - tlutfmt); + u32 row_stride = bytes_per_block * (expandedWidth / bsw); + g_texture_cache->DecodeTextureOnGPU(entry, 0, src_data, texture_size, texformat, width, + height, expandedWidth, expandedHeight, row_stride, tlut, + tlutfmt); } else { - u8* src_data_gb = - &texMem[bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE]; - TexDecoder_DecodeRGBA8FromTmem(dst_buffer, src_data, src_data_gb, expandedWidth, - expandedHeight); + size_t decoded_texture_size = expandedWidth * sizeof(u32) * expandedHeight; + + // Allocate memory for all levels at once + size_t total_texture_size = decoded_texture_size; + + // For the downsample, we need 2 buffers; 1 is 1/4 of the original texture, the other 1/16 + size_t mip_downsample_buffer_size = decoded_texture_size * 5 / 16; + + size_t prev_level_size = decoded_texture_size; + for (u32 i = 1; i < tex_levels; ++i) + { + prev_level_size /= 4; + total_texture_size += prev_level_size; + } + + // Add space for the downsampling at the end + total_texture_size += mip_downsample_buffer_size; + + CheckTempSize(total_texture_size); + dst_buffer = temp; + if (!(texformat == TextureFormat::RGBA8 && from_tmem)) + { + TexDecoder_Decode(dst_buffer, src_data, expandedWidth, expandedHeight, texformat, tlut, + tlutfmt); + } + else + { + u8* src_data_gb = &texMem[tmem_address_odd]; + TexDecoder_DecodeRGBA8FromTmem(dst_buffer, src_data, src_data_gb, expandedWidth, + expandedHeight); + } + + entry->texture->Load(0, width, height, expandedWidth, dst_buffer, decoded_texture_size); + + arbitrary_mip_detector.AddLevel(width, height, expandedWidth, dst_buffer); + + dst_buffer += decoded_texture_size; } - - entry->texture->Load(0, width, height, expandedWidth, dst_buffer, decoded_texture_size); - - arbitrary_mip_detector.AddLevel(width, height, expandedWidth, dst_buffer); - - dst_buffer += decoded_texture_size; } iter = textures_by_address.emplace(address, entry); - if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || - std::max(texture_size, palette_size) <= - (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) + if (textureCacheSafetyColorSampleSize == 0 || + std::max(texture_size, palette_size) <= (u32)textureCacheSafetyColorSampleSize * 8) { entry->textures_by_hash_iter = textures_by_hash.emplace(full_hash, entry); } - entry->SetGeneralParameters(address, texture_size, full_format); + entry->SetGeneralParameters(address, texture_size, full_format, false); entry->SetDimensions(nativeW, nativeH, tex_levels); entry->SetHashes(base_hash, full_hash); - entry->is_efb_copy = false; entry->is_custom_tex = hires_tex != nullptr; entry->memory_stride = entry->BytesPerRow(); + entry->SetNotCopy(); std::string basename = ""; if (g_ActiveConfig.bDumpTextures && !hires_tex) @@ -1025,9 +1043,8 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) const u8* ptr_odd = nullptr; if (from_tmem) { - ptr_even = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE + - texture_size]; - ptr_odd = &texMem[bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE]; + ptr_even = &texMem[tmem_address_even + texture_size]; + ptr_odd = &texMem[tmem_address_odd]; } for (u32 level = 1; level != texLevels; ++level) @@ -1081,13 +1098,422 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) entry = DoPartialTextureUpdates(iter->second, &texMem[tlutaddr], tlutfmt); - return ReturnEntry(stage, entry); + return entry; +} + +TextureCacheBase::TCacheEntry* +TextureCacheBase::GetXFBTexture(u32 address, u32 width, u32 height, TextureFormat tex_format, + int texture_cache_safety_color_sample_size) +{ + auto tex_info = ComputeTextureInformation(address, width, height, tex_format, + texture_cache_safety_color_sample_size, false, 0, 0, 0, + TLUTFormat::IA8, 1); + if (!tex_info) + { + return nullptr; + } + + const TextureLookupInformation tex_info_value = tex_info.value(); + + TCacheEntry* entry = GetXFBFromCache(tex_info_value); + if (entry != nullptr) + { + return entry; + } + + entry = CreateNormalTexture(tex_info.value()); + + // XFBs created for the purpose of being a container for textures from memory + // or as a container for overlapping textures, never need to be combined + // with other textures + entry->may_have_overlapping_textures = false; + + // At this point, the XFB wasn't found in cache + // this means the address is most likely not pointing at an xfb copy but instead + // an area of memory. Let's attempt to stitch all entries in this memory space + // together + bool loaded_from_overlapping = LoadTextureFromOverlappingTextures(entry, tex_info_value); + + if (!loaded_from_overlapping) + { + // At this point, the xfb address is truly "bogus" + // it likely is an area of memory defined by the CPU + // so load it from memory + LoadTextureFromMemory(entry, tex_info_value); + } + + if (g_ActiveConfig.bDumpXFBTarget) + { + // While this isn't really an xfb copy, we can treat it as such + // for dumping purposes + static int xfb_count = 0; + const std::string xfb_type = loaded_from_overlapping ? "combined" : "from_memory"; + entry->texture->Save(StringFromFormat("%sxfb_%s_%i.png", + File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), + xfb_type.c_str(), xfb_count++), + 0); + } + + return entry; +} + +std::optional TextureCacheBase::ComputeTextureInformation( + u32 address, u32 width, u32 height, TextureFormat tex_format, + int texture_cache_safety_color_sample_size, bool from_tmem, u32 tmem_address_even, + u32 tmem_address_odd, u32 tlut_address, TLUTFormat tlut_format, u32 levels) +{ + TextureLookupInformation tex_info; + + tex_info.from_tmem = from_tmem; + tex_info.tmem_address_even = tmem_address_even; + tex_info.tmem_address_odd = tmem_address_odd; + + tex_info.address = address; + + if (from_tmem) + tex_info.src_data = &texMem[tex_info.tmem_address_even]; + else + tex_info.src_data = Memory::GetPointer(tex_info.address); + + if (tex_info.src_data == nullptr) + { + ERROR_LOG(VIDEO, "Trying to use an invalid texture address 0x%8x", tex_info.address); + return {}; + } + + tex_info.texture_cache_safety_color_sample_size = texture_cache_safety_color_sample_size; + + // TexelSizeInNibbles(format) * width * height / 16; + tex_info.block_width = TexDecoder_GetBlockWidthInTexels(tex_format); + tex_info.block_height = TexDecoder_GetBlockHeightInTexels(tex_format); + + tex_info.bytes_per_block = (tex_info.block_width * tex_info.block_height * + TexDecoder_GetTexelSizeInNibbles(tex_format)) / + 2; + + tex_info.expanded_width = Common::AlignUp(width, tex_info.block_width); + tex_info.expanded_height = Common::AlignUp(height, tex_info.block_height); + + tex_info.total_bytes = TexDecoder_GetTextureSizeInBytes(tex_info.expanded_width, + tex_info.expanded_height, tex_format); + + tex_info.native_width = width; + tex_info.native_height = height; + tex_info.native_levels = levels; + + // GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in + // the mipmap chain + // e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we + // limit the mipmap count to 6 there + tex_info.computed_levels = std::min( + IntLog2(std::max(tex_info.native_width, tex_info.native_height)) + 1, tex_info.native_levels); + + tex_info.full_format = TextureAndTLUTFormat(tex_format, tlut_format); + tex_info.tlut_address = tlut_address; + + // TODO: This doesn't hash GB tiles for preloaded RGBA8 textures (instead, it's hashing more data + // from the low tmem bank than it should) + tex_info.base_hash = GetHash64(tex_info.src_data, tex_info.total_bytes, + tex_info.texture_cache_safety_color_sample_size); + + tex_info.is_palette_texture = IsColorIndexed(tex_format); + + if (tex_info.is_palette_texture) + { + tex_info.palette_size = TexDecoder_GetPaletteSize(tex_format); + tex_info.full_hash = + tex_info.base_hash ^ GetHash64(&texMem[tex_info.tlut_address], tex_info.palette_size, + tex_info.texture_cache_safety_color_sample_size); + } + else + { + tex_info.full_hash = tex_info.base_hash; + } + + return tex_info; +} + +TextureCacheBase::TCacheEntry* +TextureCacheBase::GetXFBFromCache(const TextureLookupInformation& tex_info) +{ + auto iter_range = textures_by_address.equal_range(tex_info.address); + TexAddrCache::iterator iter = iter_range.first; + + while (iter != iter_range.second) + { + TCacheEntry* entry = iter->second; + + if ((entry->is_xfb_copy || entry->format.texfmt == TextureFormat::XFB) && + entry->native_width == tex_info.native_width && + static_cast(entry->native_height * entry->y_scale) == + tex_info.native_height && + entry->memory_stride == entry->BytesPerRow() && !entry->may_have_overlapping_textures) + { + if (tex_info.base_hash == entry->hash && !entry->reference_changed) + { + return entry; + } + else + { + // At this point, we either have an xfb copy that has changed its hash + // or an xfb created by stitching or from memory that has been changed + // we are safe to invalidate this + iter = InvalidateTexture(iter); + continue; + } + } + + ++iter; + } + + return nullptr; +} + +bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_update, + const TextureLookupInformation& tex_info) +{ + bool updated_entry = false; + + u32 numBlocksX = entry_to_update->native_width / tex_info.block_width; + + auto iter = FindOverlappingTextures(entry_to_update->addr, entry_to_update->size_in_bytes); + while (iter.first != iter.second) + { + TCacheEntry* entry = iter.first->second; + if (entry != entry_to_update && entry->IsCopy() && !entry->tmem_only && + entry->references.count(entry_to_update) == 0 && + entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes) && + entry->memory_stride == entry_to_update->memory_stride) + { + if (entry->hash == entry->CalculateHash()) + { + if (tex_info.is_palette_texture) + { + TCacheEntry* decoded_entry = + ApplyPaletteToEntry(entry, nullptr, tex_info.full_format.tlutfmt); + if (decoded_entry) + { + // Link the efb copy with the partially updated texture, so we won't apply this partial + // update again + entry->CreateReference(entry_to_update); + // Mark the texture update as used, as if it was loaded directly + entry->frameCount = FRAMECOUNT_INVALID; + entry = decoded_entry; + } + else + { + ++iter.first; + continue; + } + } + + s32 src_x, src_y, dst_x, dst_y; + + // Note for understanding the math: + // Normal textures can't be strided, so the 2 missing cases with src_x > 0 don't exist + if (entry->addr >= entry_to_update->addr) + { + s32 block_offset = (entry->addr - entry_to_update->addr) / tex_info.bytes_per_block; + s32 block_x = block_offset % numBlocksX; + s32 block_y = block_offset / numBlocksX; + src_x = 0; + src_y = 0; + dst_x = block_x * tex_info.block_width; + dst_y = block_y * tex_info.block_height; + } + else + { + s32 block_offset = (entry_to_update->addr - entry->addr) / tex_info.bytes_per_block; + s32 block_x = block_offset % numBlocksX; + s32 block_y = block_offset / numBlocksX; + src_x = block_x * tex_info.block_width; + src_y = block_y * tex_info.block_height; + dst_x = 0; + dst_y = 0; + } + + u32 copy_width = + std::min(entry->native_width - src_x, entry_to_update->native_width - dst_x); + u32 copy_height = + std::min((entry->native_height * entry->y_scale) - src_y, + (entry_to_update->native_height * entry_to_update->y_scale) - dst_y); + + // If one of the textures is scaled, scale both with the current efb scaling factor + if (entry_to_update->native_width != entry_to_update->GetWidth() || + (entry_to_update->native_height * entry_to_update->y_scale) != + entry_to_update->GetHeight() || + entry->native_width != entry->GetWidth() || + (entry->native_height * entry->y_scale) != entry->GetHeight()) + { + ScaleTextureCacheEntryTo( + entry_to_update, g_renderer->EFBToScaledX(entry_to_update->native_width), + g_renderer->EFBToScaledY(entry_to_update->native_height * entry_to_update->y_scale)); + ScaleTextureCacheEntryTo(entry, g_renderer->EFBToScaledX(entry->native_width), + g_renderer->EFBToScaledY(entry->native_height * entry->y_scale)); + + src_x = g_renderer->EFBToScaledX(src_x); + src_y = g_renderer->EFBToScaledY(src_y); + dst_x = g_renderer->EFBToScaledX(dst_x); + dst_y = g_renderer->EFBToScaledY(dst_y); + copy_width = g_renderer->EFBToScaledX(copy_width); + copy_height = g_renderer->EFBToScaledY(copy_height); + } + + MathUtil::Rectangle srcrect, dstrect; + srcrect.left = src_x; + srcrect.top = src_y; + srcrect.right = (src_x + copy_width); + srcrect.bottom = (src_y + copy_height); + + if (static_cast(entry->GetWidth()) == srcrect.GetWidth()) + { + srcrect.right -= 1; + } + + if (static_cast(entry->GetHeight()) == srcrect.GetHeight()) + { + srcrect.bottom -= 1; + } + + dstrect.left = dst_x; + dstrect.top = dst_y; + dstrect.right = (dst_x + copy_width); + dstrect.bottom = (dst_y + copy_height); + + if (static_cast(entry_to_update->GetWidth()) == dstrect.GetWidth()) + { + dstrect.right -= 1; + } + + if (static_cast(entry_to_update->GetHeight()) == dstrect.GetHeight()) + { + dstrect.bottom -= 1; + } + + entry_to_update->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, dstrect); + + updated_entry = true; + + if (tex_info.is_palette_texture) + { + // Remove the temporary converted texture, it won't be used anywhere else + // TODO: It would be nice to convert and copy in one step, but this code path isn't common + InvalidateTexture(GetTexCacheIter(entry)); + } + else + { + // Link the two textures together, so we won't apply this partial update again + entry->CreateReference(entry_to_update); + // Mark the texture update as used, as if it was loaded directly + entry->frameCount = FRAMECOUNT_INVALID; + } + } + else + { + // If the hash does not match, this EFB copy will not be used for anything, so remove it + iter.first = InvalidateTexture(iter.first); + continue; + } + } + ++iter.first; + } + + return updated_entry; +} + +TextureCacheBase::TCacheEntry* +TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info) +{ + // create the entry/texture + TextureConfig config; + config.width = tex_info.native_width; + config.height = tex_info.native_height; + config.levels = tex_info.computed_levels; + config.format = AbstractTextureFormat::RGBA8; + config.rendertarget = true; + + TCacheEntry* entry = AllocateCacheEntry(config); + GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); + + if (!entry) + return nullptr; + + textures_by_address.emplace(tex_info.address, entry); + if (tex_info.texture_cache_safety_color_sample_size == 0 || + std::max(tex_info.total_bytes, tex_info.palette_size) <= + (u32)tex_info.texture_cache_safety_color_sample_size * 8) + { + entry->textures_by_hash_iter = textures_by_hash.emplace(tex_info.full_hash, entry); + } + + entry->SetGeneralParameters(tex_info.address, tex_info.total_bytes, tex_info.full_format, false); + entry->SetDimensions(tex_info.native_width, tex_info.native_height, tex_info.computed_levels); + entry->SetHashes(tex_info.base_hash, tex_info.full_hash); + entry->is_custom_tex = false; + entry->memory_stride = entry->BytesPerRow(); + entry->SetNotCopy(); + + INCSTAT(stats.numTexturesUploaded); + SETSTAT(stats.numTexturesAlive, textures_by_address.size()); + + return entry; +} + +void TextureCacheBase::LoadTextureFromMemory(TCacheEntry* entry_to_update, + const TextureLookupInformation& tex_info) +{ + // We can decode on the GPU if it is a supported format and the flag is enabled. + // Currently we don't decode RGBA8 textures from Tmem, as that would require copying from both + // banks, and if we're doing an copy we may as well just do the whole thing on the CPU, since + // there's no conversion between formats. In the future this could be extended with a separate + // shader, however. + bool decode_on_gpu = g_ActiveConfig.UseGPUTextureDecoding() && + g_texture_cache->SupportsGPUTextureDecode(tex_info.full_format.texfmt, + tex_info.full_format.tlutfmt) && + !(tex_info.from_tmem && tex_info.full_format.texfmt == TextureFormat::RGBA8); + + LoadTextureLevelZeroFromMemory(entry_to_update, tex_info, decode_on_gpu); +} + +void TextureCacheBase::LoadTextureLevelZeroFromMemory(TCacheEntry* entry_to_update, + const TextureLookupInformation& tex_info, + bool decode_on_gpu) +{ + const u8* tlut = &texMem[tex_info.tlut_address]; + + if (decode_on_gpu) + { + u32 row_stride = tex_info.bytes_per_block * (tex_info.expanded_width / tex_info.block_width); + g_texture_cache->DecodeTextureOnGPU( + entry_to_update, 0, tex_info.src_data, tex_info.total_bytes, tex_info.full_format.texfmt, + tex_info.native_width, tex_info.native_height, tex_info.expanded_width, + tex_info.expanded_height, row_stride, tlut, tex_info.full_format.tlutfmt); + } + else + { + size_t decoded_texture_size = tex_info.expanded_width * sizeof(u32) * tex_info.expanded_height; + CheckTempSize(decoded_texture_size); + if (!(tex_info.full_format.texfmt == TextureFormat::RGBA8 && tex_info.from_tmem)) + { + TexDecoder_Decode(temp, tex_info.src_data, tex_info.expanded_width, tex_info.expanded_height, + tex_info.full_format.texfmt, tlut, tex_info.full_format.tlutfmt); + } + else + { + u8* src_data_gb = &texMem[tex_info.tmem_address_odd]; + TexDecoder_DecodeRGBA8FromTmem(temp, tex_info.src_data, src_data_gb, tex_info.expanded_width, + tex_info.expanded_height); + } + + entry_to_update->texture->Load(0, tex_info.native_width, tex_info.native_height, + tex_info.expanded_width, temp, decoded_texture_size); + } } void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstFormat, u32 dstStride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, - bool scaleByHalf) + bool scaleByHalf, float y_scale, float gamma) { // Emulation methods: // @@ -1160,6 +1586,11 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF PEControl::PixelFormat srcFormat = bpmem.zcontrol.pixel_format; bool efbHasAlpha = srcFormat == PEControl::RGBA6_Z24; + bool copy_to_ram = + !g_ActiveConfig.bSkipEFBCopyToRam || g_ActiveConfig.backend_info.bForceCopyToRam; + bool copy_to_vram = g_ActiveConfig.backend_info.bSupportsCopyToVram; + bool is_xfb_copy = false; + if (is_depth_copy) { switch (dstFormat) @@ -1388,6 +1819,16 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF } break; + case EFBCopyFormat::XFB: // XFB copy, we just pretend it's an RGBX copy + colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; + ColorMask[3] = 0.0f; + fConstAdd[3] = 1.0f; + cbufid = 30; // just re-use the RGBX8 cbufid from above + copy_to_ram = + !g_ActiveConfig.bSkipXFBCopyToRam || g_ActiveConfig.backend_info.bForceCopyToRam; + is_xfb_copy = true; + break; + default: ERROR_LOG(VIDEO, "Unknown copy color format: 0x%X", static_cast(dstFormat)); colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; @@ -1418,7 +1859,7 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF const u32 blockW = TexDecoder_GetBlockWidthInTexels(baseFormat); // Round up source height to multiple of block size - u32 actualHeight = Common::AlignUp(tex_h, blockH); + u32 actualHeight = Common::AlignUp(static_cast(tex_h * y_scale), blockH); const u32 actualWidth = Common::AlignUp(tex_w, blockW); u32 num_blocks_y = actualHeight / blockH; @@ -1430,24 +1871,28 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF const u32 bytes_per_row = num_blocks_x * bytes_per_block; const u32 covered_range = num_blocks_y * dstStride; - bool copy_to_ram = !g_ActiveConfig.bSkipEFBCopyToRam; - bool copy_to_vram = true; - if (copy_to_ram) { - EFBCopyParams format(srcFormat, dstFormat, is_depth_copy, isIntensity); + EFBCopyParams format(srcFormat, dstFormat, is_depth_copy, isIntensity, y_scale); CopyEFB(dst, format, tex_w, bytes_per_row, num_blocks_y, dstStride, srcRect, scaleByHalf); } else { - // Hack: Most games don't actually need the correct texture data in RAM - // and we can just keep a copy in VRAM. We zero the memory so we - // can check it hasn't changed before using our copy in VRAM. - u8* ptr = dst; - for (u32 i = 0; i < num_blocks_y; i++) + if (is_xfb_copy) { - memset(ptr, 0, bytes_per_row); - ptr += dstStride; + UninitializeXFBMemory(dst, dstStride, bytes_per_row, num_blocks_y); + } + else + { + // Hack: Most games don't actually need the correct texture data in RAM + // and we can just keep a copy in VRAM. We zero the memory so we + // can check it hasn't changed before using our copy in VRAM. + u8* ptr = dst; + for (u32 i = 0; i < num_blocks_y; i++) + { + memset(ptr, 0, bytes_per_row); + ptr += dstStride; + } } } @@ -1487,6 +1932,15 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF while (iter.first != iter.second) { TCacheEntry* entry = iter.first->second; + + if (entry->addr == dstAddr && entry->is_xfb_copy) + { + for (auto& reference : entry->references) + { + reference->reference_changed = true; + } + } + if (entry->OverlapsMemoryRange(dstAddr, covered_range)) { u32 overlap_range = std::min(entry->addr + entry->size_in_bytes, dstAddr + covered_range) - @@ -1500,6 +1954,19 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF } entry->may_have_overlapping_textures = true; + // There are cases (Rogue Squadron 2 / Texas Holdem on Wiiware) where + // for xfb copies the textures overlap which causes the hash of the first copy + // to be different (from when it was originally created). This has no implications + // for XFB2Tex because the underlying memory doesn't change (dummy values) but + // can affect XFB2Ram when we compare the texture cache copy hash with the + // newly computed hash + // By calculating the hash when we receive overlapping xfbs, we are able + // to mitigate this + if (entry->is_xfb_copy && copy_to_ram) + { + entry->hash = entry->CalculateHash(); + } + // Do not load textures by hash, if they were at least partly overwritten by an efb copy. // In this case, comparing the hash is not enough to check, if two textures are identical. if (entry->textures_by_hash_iter != textures_by_hash.end()) @@ -1524,11 +1991,21 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF if (entry) { - entry->SetGeneralParameters(dstAddr, 0, baseFormat); + entry->SetGeneralParameters(dstAddr, 0, baseFormat, is_xfb_copy); entry->SetDimensions(tex_w, tex_h, 1); + entry->y_scale = y_scale; + entry->gamma = gamma; entry->frameCount = FRAMECOUNT_INVALID; - entry->SetEfbCopy(dstStride); + if (is_xfb_copy) + { + entry->should_force_safe_hashing = is_xfb_copy; + entry->SetXfbCopy(dstStride); + } + else + { + entry->SetEfbCopy(dstStride); + } entry->may_have_overlapping_textures = false; entry->is_custom_tex = false; @@ -1537,12 +2014,21 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF u64 hash = entry->CalculateHash(); entry->SetHashes(hash, hash); - if (g_ActiveConfig.bDumpEFBTarget) + if (g_ActiveConfig.bDumpEFBTarget && !is_xfb_copy) { - static int count = 0; + static int efb_count = 0; entry->texture->Save(StringFromFormat("%sefb_frame_%i.png", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), - count++), + efb_count++), + 0); + } + + if (g_ActiveConfig.bDumpXFBTarget && is_xfb_copy) + { + static int xfb_count = 0; + entry->texture->Save(StringFromFormat("%sxfb_copy_%i.png", + File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), + xfb_count++), 0); } @@ -1551,6 +2037,33 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF } } +void TextureCacheBase::UninitializeXFBMemory(u8* dst, u32 stride, u32 bytes_per_row, + u32 num_blocks_y) +{ + // Originally, we planned on using a 'key color' + // for alpha to address partial xfbs (Mario Strikers / Chicken Little). + // This work was removed since it was unfinished but there + // was still a desire to differentiate between the old and the new approach + // which is why we still set uninitialized xfb memory to fuchsia + // (Y=1,U=254,V=254) instead of dark green (Y=0,U=0,V=0) in YUV + // like is done in the EFB path. + for (u32 i = 0; i < num_blocks_y; i++) + { + for (u32 offset = 0; offset < bytes_per_row; offset++) + { + if (offset % 2) + { + dst[offset] = 254; + } + else + { + dst[offset] = 1; + } + } + dst += stride; + } +} + TextureCacheBase::TCacheEntry* TextureCacheBase::AllocateCacheEntry(const TextureConfig& config) { std::unique_ptr texture = AllocateTexture(config); @@ -1561,6 +2074,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::AllocateCacheEntry(const Textur } TCacheEntry* cacheEntry = new TCacheEntry(std::move(texture)); cacheEntry->textures_by_hash_iter = textures_by_hash.end(); + cacheEntry->id = last_entry_id++; return cacheEntry; } @@ -1684,14 +2198,15 @@ u32 TextureCacheBase::TCacheEntry::NumBlocksY() const { u32 blockH = TexDecoder_GetBlockHeightInTexels(format.texfmt); // Round up source height to multiple of block size - u32 actualHeight = Common::AlignUp(native_height, blockH); + u32 actualHeight = Common::AlignUp(static_cast(native_height * y_scale), blockH); return actualHeight / blockH; } -void TextureCacheBase::TCacheEntry::SetEfbCopy(u32 stride) +void TextureCacheBase::TCacheEntry::SetXfbCopy(u32 stride) { - is_efb_copy = true; + is_efb_copy = false; + is_xfb_copy = true; memory_stride = stride; _assert_msg_(VIDEO, memory_stride >= BytesPerRow(), "Memory stride is too small"); @@ -1699,12 +2214,39 @@ void TextureCacheBase::TCacheEntry::SetEfbCopy(u32 stride) size_in_bytes = memory_stride * NumBlocksY(); } +void TextureCacheBase::TCacheEntry::SetEfbCopy(u32 stride) +{ + is_efb_copy = true; + is_xfb_copy = false; + memory_stride = stride; + + _assert_msg_(VIDEO, memory_stride >= BytesPerRow(), "Memory stride is too small"); + + size_in_bytes = memory_stride * NumBlocksY(); +} + +void TextureCacheBase::TCacheEntry::SetNotCopy() +{ + is_xfb_copy = false; + is_efb_copy = false; +} + +int TextureCacheBase::TCacheEntry::HashSampleSize() const +{ + if (should_force_safe_hashing) + { + return 0; + } + + return g_ActiveConfig.iSafeTextureCache_ColorSamples; +} + u64 TextureCacheBase::TCacheEntry::CalculateHash() const { u8* ptr = Memory::GetPointer(addr); if (memory_stride == BytesPerRow()) { - return GetHash64(ptr, size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + return GetHash64(ptr, size_in_bytes, HashSampleSize()); } else { @@ -1712,11 +2254,11 @@ u64 TextureCacheBase::TCacheEntry::CalculateHash() const u64 temp_hash = size_in_bytes; u32 samples_per_row = 0; - if (g_ActiveConfig.iSafeTextureCache_ColorSamples != 0) + if (HashSampleSize() != 0) { // Hash at least 4 samples per row to avoid hashing in a bad pattern, like just on the left // side of the efb copy - samples_per_row = std::max(g_ActiveConfig.iSafeTextureCache_ColorSamples / blocks, 4u); + samples_per_row = std::max(HashSampleSize() / blocks, 4u); } for (u32 i = 0; i < blocks; i++) diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index 6b69caf036..a9700ad68c 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -45,21 +47,59 @@ struct TextureAndTLUTFormat struct EFBCopyParams { EFBCopyParams(PEControl::PixelFormat efb_format_, EFBCopyFormat copy_format_, bool depth_, - bool yuv_) - : efb_format(efb_format_), copy_format(copy_format_), depth(depth_), yuv(yuv_) + bool yuv_, float y_scale_) + : efb_format(efb_format_), copy_format(copy_format_), depth(depth_), yuv(yuv_), + y_scale(y_scale_) { } bool operator<(const EFBCopyParams& rhs) const { - return std::tie(efb_format, copy_format, depth, yuv) < - std::tie(rhs.efb_format, rhs.copy_format, rhs.depth, rhs.yuv); + return std::tie(efb_format, copy_format, depth, yuv, y_scale) < + std::tie(rhs.efb_format, rhs.copy_format, rhs.depth, rhs.yuv, rhs.y_scale); } PEControl::PixelFormat efb_format; EFBCopyFormat copy_format; bool depth; bool yuv; + float y_scale; +}; + +struct TextureLookupInformation +{ + u32 address; + + u32 block_width; + u32 block_height; + u32 bytes_per_block; + + u32 expanded_width; + u32 expanded_height; + u32 native_width; + u32 native_height; + u32 total_bytes; + u32 native_levels = 1; + u32 computed_levels; + + u64 base_hash; + u64 full_hash; + + TextureAndTLUTFormat full_format; + u32 tlut_address = 0; + + bool is_palette_texture = false; + u32 palette_size = 0; + + bool use_mipmaps = false; + + bool from_tmem = false; + u32 tmem_address_even = 0; + u32 tmem_address_odd = 0; + + int texture_cache_safety_color_sample_size = 0; // Default to safe hashing + + u8* src_data; }; class TextureCacheBase @@ -84,6 +124,13 @@ public: bool tmem_only = false; // indicates that this texture only exists in the tmem cache bool has_arbitrary_mips = false; // indicates that the mips in this texture are arbitrary // content, aren't just downscaled + bool should_force_safe_hashing = false; // for XFB + bool is_xfb_copy = false; + float y_scale = 1.0f; + float gamma = 1.0f; + u64 id; + + bool reference_changed = false; // used by xfb to determine when a reference xfb changed unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view @@ -105,11 +152,13 @@ public: ~TCacheEntry(); - void SetGeneralParameters(u32 _addr, u32 _size, TextureAndTLUTFormat _format) + void SetGeneralParameters(u32 _addr, u32 _size, TextureAndTLUTFormat _format, + bool force_safe_hashing) { addr = _addr; size_in_bytes = _size; format = _format; + should_force_safe_hashing = force_safe_hashing; } void SetDimensions(unsigned int _native_width, unsigned int _native_height, @@ -135,16 +184,20 @@ public: other_entry->references.emplace(this); } + void SetXfbCopy(u32 stride); void SetEfbCopy(u32 stride); + void SetNotCopy(); bool OverlapsMemoryRange(u32 range_address, u32 range_size) const; bool IsEfbCopy() const { return is_efb_copy; } + bool IsCopy() const { return is_xfb_copy || is_efb_copy; } u32 NumBlocksY() const; u32 BytesPerRow() const; u64 CalculateHash() const; + int HashSampleSize() const; u32 GetWidth() const { return texture->GetConfig().width; } u32 GetHeight() const { return texture->GetConfig().height; } u32 GetNumLevels() const { return texture->GetConfig().levels; } @@ -172,10 +225,31 @@ public: TCacheEntry* Load(const u32 stage); static void InvalidateAllBindPoints() { valid_bind_points.reset(); } static bool IsValidBindPoint(u32 i) { return valid_bind_points.test(i); } - void BindTextures(); + TCacheEntry* GetTexture(u32 address, u32 width, u32 height, const TextureFormat texformat, + const int textureCacheSafetyColorSampleSize, u32 tlutaddr = 0, + TLUTFormat tlutfmt = TLUTFormat::IA8, bool use_mipmaps = false, + u32 tex_levels = 1, bool from_tmem = false, u32 tmem_address_even = 0, + u32 tmem_address_odd = 0); + + TCacheEntry* GetXFBTexture(u32 address, u32 width, u32 height, TextureFormat texformat, + int textureCacheSafetyColorSampleSize); + std::optional + ComputeTextureInformation(u32 address, u32 width, u32 height, TextureFormat texformat, + int textureCacheSafetyColorSampleSize, bool from_tmem, + u32 tmem_address_even, u32 tmem_address_odd, u32 tlutaddr, + TLUTFormat tlutfmt, u32 levels); + TCacheEntry* GetXFBFromCache(const TextureLookupInformation& tex_info); + bool LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_update, + const TextureLookupInformation& tex_info); + TCacheEntry* CreateNormalTexture(const TextureLookupInformation& tex_info); + void LoadTextureFromMemory(TCacheEntry* entry_to_update, + const TextureLookupInformation& tex_info); + void LoadTextureLevelZeroFromMemory(TCacheEntry* entry_to_update, + const TextureLookupInformation& tex_info, bool decode_on_gpu); + virtual void BindTextures(); void CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstFormat, u32 dstStride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, - bool scaleByHalf); + bool scaleByHalf, float y_scale, float gamma); virtual void ConvertTexture(TCacheEntry* entry, TCacheEntry* unconverted, const void* palette, TLUTFormat format) = 0; @@ -197,6 +271,10 @@ public: { } + void ScaleTextureCacheEntryTo(TCacheEntry* entry, u32 new_width, u32 new_height); + + virtual std::unique_ptr CreateTexture(const TextureConfig& config) = 0; + protected: TextureCacheBase(); @@ -222,7 +300,6 @@ private: TCacheEntry* ApplyPaletteToEntry(TCacheEntry* entry, u8* palette, TLUTFormat tlutfmt); - void ScaleTextureCacheEntryTo(TCacheEntry* entry, u32 new_width, u32 new_height); TCacheEntry* DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* palette, TLUTFormat tlutfmt); @@ -239,8 +316,6 @@ private: std::pair FindOverlappingTextures(u32 addr, u32 size_in_bytes); - virtual std::unique_ptr CreateTexture(const TextureConfig& config) = 0; - virtual void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half, unsigned int cbuf_id, const float* colmat) = 0; @@ -248,11 +323,12 @@ private: // Removes and unlinks texture from texture cache and returns it to the pool TexAddrCache::iterator InvalidateTexture(TexAddrCache::iterator t_iter); - TCacheEntry* ReturnEntry(unsigned int stage, TCacheEntry* entry); + void UninitializeXFBMemory(u8* dst, u32 stride, u32 bytes_per_row, u32 num_blocks_y); TexAddrCache textures_by_address; TexHashCache textures_by_hash; TexPool texture_pool; + u64 last_entry_id = 0; // Backup configuration values struct BackupConfig diff --git a/Source/Core/VideoCommon/TextureConversionShader.cpp b/Source/Core/VideoCommon/TextureConversionShader.cpp index ab1b284b78..ad31c2bf9f 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/TextureConversionShader.cpp @@ -49,6 +49,8 @@ u16 GetEncodedSampleCount(EFBCopyFormat format) case EFBCopyFormat::RG8: case EFBCopyFormat::GB8: return 2; + case EFBCopyFormat::XFB: + return 2; default: PanicAlert("Invalid EFB Copy Format (0x%X)! (GetEncodedSampleCount)", static_cast(format)); return 1; @@ -62,9 +64,13 @@ static void WriteSwizzler(char*& p, EFBCopyFormat format, APIType ApiType) // left, top, of source rectangle within source texture // width of the destination rectangle, scale_factor (1 or 2) if (ApiType == APIType::Vulkan) - WRITE(p, "layout(std140, push_constant) uniform PCBlock { int4 position; } PC;\n"); + WRITE(p, + "layout(std140, push_constant) uniform PCBlock { int4 position; float y_scale; } PC;\n"); else + { WRITE(p, "uniform int4 position;\n"); + WRITE(p, "uniform float y_scale;\n"); + } // Alpha channel in the copy is set to 1 the EFB format does not have an alpha channel. WRITE(p, "float4 RGBA8ToRGB8(float4 src)\n"); @@ -109,7 +115,8 @@ static void WriteSwizzler(char*& p, EFBCopyFormat format, APIType ApiType) WRITE(p, "{\n" " int2 sampleUv;\n" " int2 uv1 = int2(gl_FragCoord.xy);\n" - " int4 position = PC.position;\n"); + " int4 position = PC.position;\n" + " float y_scale = PC.y_scale;\n"); } else // D3D { @@ -148,6 +155,7 @@ static void WriteSwizzler(char*& p, EFBCopyFormat format, APIType ApiType) // pixel) WRITE(p, " uv0 += float2(position.xy);\n"); // move to copied rect WRITE(p, " uv0 /= float2(%d, %d);\n", EFB_WIDTH, EFB_HEIGHT); // normalize to [0:1] + WRITE(p, " uv0 /= float2(1, y_scale);\n"); // apply the y scaling if (ApiType == APIType::OpenGL) // ogl has to flip up and down { WRITE(p, " uv0.y = 1.0-uv0.y;\n"); @@ -656,6 +664,28 @@ static void WriteZ24Encoder(char*& p, APIType ApiType, const EFBCopyParams& para WriteEncoderEnd(p); } +static void WriteXFBEncoder(char*& p, APIType ApiType, const EFBCopyParams& params) +{ + WriteSwizzler(p, EFBCopyFormat::XFB, ApiType); + + WRITE(p, " float3 y_const = float3(0.257, 0.504, 0.098);\n"); + WRITE(p, " float3 u_const = float3(-0.148, -0.291, 0.439);\n"); + WRITE(p, " float3 v_const = float3(0.439, -0.368, -0.071);\n"); + WRITE(p, " float3 color0;\n"); + WRITE(p, " float3 color1;\n"); + + WriteSampleColor(p, "rgb", "color0", 0, ApiType, params); + WriteSampleColor(p, "rgb", "color1", 1, ApiType, params); + WRITE(p, " float3 average = (color0 + color1) * 0.5;\n"); + + WRITE(p, " ocol0.b = dot(color0, y_const) + 0.0625;\n"); + WRITE(p, " ocol0.g = dot(average, u_const) + 0.5;\n"); + WRITE(p, " ocol0.r = dot(color1, y_const) + 0.0625;\n"); + WRITE(p, " ocol0.a = dot(average, v_const) + 0.5;\n"); + + WriteEncoderEnd(p); +} + const char* GenerateEncodingShader(const EFBCopyParams& params, APIType api_type) { text[sizeof(text) - 1] = 0x7C; // canary @@ -728,6 +758,9 @@ const char* GenerateEncodingShader(const EFBCopyParams& params, APIType api_type else WriteCC8Encoder(p, "gb", api_type, params); break; + case EFBCopyFormat::XFB: + WriteXFBEncoder(p, api_type, params); + break; default: PanicAlert("Invalid EFB Copy Format (0x%X)! (GenerateEncodingShader)", static_cast(params.copy_format)); @@ -1230,12 +1263,41 @@ static const std::map s_decoding_shader_info{ vec4 norm_color = GetPaletteColorNormalized(index); imageStore(output_image, ivec3(ivec2(coords), 0), norm_color); } + )"}}, + + // We do the inverse BT.601 conversion for YCbCr to RGB + // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion + {TextureFormat::XFB, + {BUFFER_FORMAT_RGBA8_UINT, 0, 8, 8, false, + R"( + layout(local_size_x = 8, local_size_y = 8) in; + + void main() + { + uvec2 uv = gl_GlobalInvocationID.xy; + int buffer_pos = int(u_src_offset + (uv.y * u_src_row_stride) + (uv.x / 2)); + vec4 yuyv = texelFetch(s_input_buffer, buffer_pos); + + float y = mix(yuyv.r, yuyv.b, (uv.x & 1u) == 1u); + + float yComp = 1.164 * (y - 16); + float uComp = yuyv.g - 128; + float vComp = yuyv.a - 128; + + vec4 rgb = vec4(yComp + (1.596 * vComp), + yComp - (0.813 * vComp) - (0.391 * uComp), + yComp + (2.018 * uComp), + 255.0); + vec4 rgba_norm = rgb / 255.0; + imageStore(output_image, ivec3(ivec2(uv), 0), rgba_norm); + } )"}}}; static const std::array s_buffer_bytes_per_texel = {{ 1, // BUFFER_FORMAT_R8_UINT 2, // BUFFER_FORMAT_R16_UINT 8, // BUFFER_FORMAT_R32G32_UINT + 4, // BUFFER_FORMAT_RGBA8_UINT }}; const DecodingShaderInfo* GetDecodingShaderInfo(TextureFormat format) diff --git a/Source/Core/VideoCommon/TextureConversionShader.h b/Source/Core/VideoCommon/TextureConversionShader.h index 9b1feb8b45..2680cd3c5b 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.h +++ b/Source/Core/VideoCommon/TextureConversionShader.h @@ -27,6 +27,7 @@ enum BufferFormat BUFFER_FORMAT_R8_UINT, BUFFER_FORMAT_R16_UINT, BUFFER_FORMAT_R32G32_UINT, + BUFFER_FORMAT_RGBA8_UINT, BUFFER_FORMAT_COUNT }; diff --git a/Source/Core/VideoCommon/TextureDecoder.h b/Source/Core/VideoCommon/TextureDecoder.h index 1a33fbfcf8..2a270eacd1 100644 --- a/Source/Core/VideoCommon/TextureDecoder.h +++ b/Source/Core/VideoCommon/TextureDecoder.h @@ -28,6 +28,11 @@ enum class TextureFormat C8 = 0x9, C14X2 = 0xA, CMPR = 0xE, + + // Special texture format used to represent YUVY xfb copies. + // They aren't really textures, but they share so much hardware and usecases that it makes sense + // to emulate them as part of texture cache. + XFB = 0xF, }; static inline bool IsColorIndexed(TextureFormat format) @@ -73,6 +78,11 @@ enum class EFBCopyFormat B8 = 0xA, // B8, Z8L RG8 = 0xB, // RG8, Z16R (Note: G and R are reversed) GB8 = 0xC, // GB8, Z16L + + // Special texture format used to represent YUVY xfb copies. + // They aren't really textures, but they share so much hardware and usecases that it makes sense + // to emulate them as part of texture cache. + XFB = 0xF, }; enum class TLUTFormat diff --git a/Source/Core/VideoCommon/TextureDecoder_Common.cpp b/Source/Core/VideoCommon/TextureDecoder_Common.cpp index 52debad57b..9dd9f5850c 100644 --- a/Source/Core/VideoCommon/TextureDecoder_Common.cpp +++ b/Source/Core/VideoCommon/TextureDecoder_Common.cpp @@ -4,8 +4,10 @@ #include #include +#include #include "Common/CommonTypes.h" +#include "Common/MathUtil.h" #include "Common/MsgHandler.h" #include "Common/Swap.h" @@ -46,6 +48,9 @@ int TexDecoder_GetTexelSizeInNibbles(TextureFormat format) // Compressed format case TextureFormat::CMPR: return 1; + // Special formats + case TextureFormat::XFB: + return 4; default: PanicAlert("Invalid Texture Format (0x%X)! (GetTexelSizeInNibbles)", static_cast(format)); return 1; @@ -82,6 +87,9 @@ int TexDecoder_GetBlockWidthInTexels(TextureFormat format) // Compressed format case TextureFormat::CMPR: return 8; + // Special formats + case TextureFormat::XFB: + return 16; default: PanicAlert("Invalid Texture Format (0x%X)! (GetBlockWidthInTexels)", static_cast(format)); return 8; @@ -113,6 +121,9 @@ int TexDecoder_GetBlockHeightInTexels(TextureFormat format) // Compressed format case TextureFormat::CMPR: return 8; + // Special formats + case TextureFormat::XFB: + return 1; default: PanicAlert("Invalid Texture Format (0x%X)! (GetBlockHeightInTexels)", static_cast(format)); return 4; @@ -144,6 +155,9 @@ int TexDecoder_GetEFBCopyBlockWidthInTexels(EFBCopyFormat format) // 32-bit formats case EFBCopyFormat::RGBA8: return 4; + // Special formats + case EFBCopyFormat::XFB: + return 16; default: PanicAlert("Invalid EFB Copy Format (0x%X)! (GetEFBCopyBlockWidthInTexels)", static_cast(format)); @@ -176,6 +190,9 @@ int TexDecoder_GetEFBCopyBlockHeightInTexels(EFBCopyFormat format) // 32-bit formats case EFBCopyFormat::RGBA8: return 4; + // Special formats + case EFBCopyFormat::XFB: + return 1; default: PanicAlert("Invalid EFB Copy Format (0x%X)! (GetEFBCopyBlockHeightInTexels)", static_cast(format)); @@ -226,6 +243,8 @@ TextureFormat TexDecoder_GetEFBCopyBaseFormat(EFBCopyFormat format) return TextureFormat::RGB5A3; case EFBCopyFormat::RGBA8: return TextureFormat::RGBA8; + case EFBCopyFormat::XFB: + return TextureFormat::XFB; default: PanicAlert("Invalid EFB Copy Format (0x%X)! (GetEFBCopyBaseFormat)", static_cast(format)); return static_cast(format); @@ -247,7 +266,7 @@ static const char* texfmt[] = { "0x1C", "0x1D", "0x1E", "0x1F", // pixel + copy "CR4", "0x21", "CRA4", "CRA8", "0x24", "0x25", "CYUVA8", "CA8", "CR8", "CG8", "CB8", "CRG8", - "CGB8", "0x2D", "0x2E", "0x2F", + "CGB8", "0x2D", "0x2E", "XFB", // Z + copy "CZ4", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", "0x38", "CZ8M", "CZ8L", "0x3B", "CZ16L", "0x3D", "0x3E", "0x3F", @@ -619,6 +638,23 @@ void TexDecoder_DecodeTexel(u8* dst, const u8* src, int s, int t, int imageWidth *((u32*)dst) = color; } break; + case TextureFormat::XFB: + { + size_t offset = (t * imageWidth + (s & (~1))) * 2; + + // We do this one color sample (aka 2 RGB pixles) at a time + int Y = int((s & 1) == 0 ? src[offset] : src[offset + 2]) - 16; + int U = int(src[offset + 1]) - 128; + int V = int(src[offset + 3]) - 128; + + // We do the inverse BT.601 conversion for YCbCr to RGB + // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion + u8 R = MathUtil::Clamp(int(1.164f * Y + 1.596f * V), 0, 255); + u8 G = MathUtil::Clamp(int(1.164f * Y - 0.392f * U - 0.813f * V), 0, 255); + u8 B = MathUtil::Clamp(int(1.164f * Y + 2.017f * U), 0, 255); + dst[t * imageWidth + s] = 0xff000000 | B << 16 | G << 8 | R; + } + break; } } diff --git a/Source/Core/VideoCommon/TextureDecoder_x64.cpp b/Source/Core/VideoCommon/TextureDecoder_x64.cpp index 135fc60629..8a55bb5a53 100644 --- a/Source/Core/VideoCommon/TextureDecoder_x64.cpp +++ b/Source/Core/VideoCommon/TextureDecoder_x64.cpp @@ -9,6 +9,7 @@ #include "Common/CPUDetect.h" #include "Common/CommonTypes.h" #include "Common/Intrinsics.h" +#include "Common/MathUtil.h" #include "Common/MsgHandler.h" #include "Common/Swap.h" @@ -1486,6 +1487,39 @@ void _TexDecoder_DecodeImpl(u32* dst, const u8* src, int width, int height, Text TexDecoder_DecodeImpl_CMPR(dst, src, width, height, texformat, tlut, tlutfmt, Wsteps4, Wsteps8); break; + case TextureFormat::XFB: + { + for (int y = 0; y < height; y += 1) + { + for (int x = 0; x < width; x += 2) + { + size_t offset = static_cast((y * width + x) * 2); + + // We do this one color sample (aka 2 RGB pixles) at a time + int Y1 = int(src[offset]) - 16; + int U = int(src[offset + 1]) - 128; + int Y2 = int(src[offset + 2]) - 16; + int V = int(src[offset + 3]) - 128; + + // We do the inverse BT.601 conversion for YCbCr to RGB + // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion + u8 R1 = static_cast(MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255)); + u8 G1 = + static_cast(MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255)); + u8 B1 = static_cast(MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U), 0, 255)); + + u8 R2 = static_cast(MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255)); + u8 G2 = + static_cast(MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255)); + u8 B2 = static_cast(MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U), 0, 255)); + + dst[y * width + x] = 0xff000000 | B1 << 16 | G1 << 8 | R1; + dst[y * width + x + 1] = 0xff000000 | B2 << 16 | G2 << 8 | R2; + } + } + } + break; + default: PanicAlert("Invalid Texture Format (0x%X)! (_TexDecoder_DecodeImpl)", static_cast(texformat)); diff --git a/Source/Core/VideoCommon/VideoBackendBase.h b/Source/Core/VideoCommon/VideoBackendBase.h index 16d25c7eab..b7d6e1faa8 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.h +++ b/Source/Core/VideoCommon/VideoBackendBase.h @@ -47,7 +47,9 @@ public: virtual void Video_Prepare() = 0; void Video_ExitLoop(); - virtual void Video_Cleanup() = 0; // called from gl/d3d thread + + void Video_CleanupShared(); // called from gl/d3d thread + virtual void Video_Cleanup() = 0; void Video_BeginField(u32, u32, u32, u32, u64); diff --git a/Source/Core/VideoCommon/VideoCommon.h b/Source/Core/VideoCommon/VideoCommon.h index e25b2b66a5..4bd5f59209 100644 --- a/Source/Core/VideoCommon/VideoCommon.h +++ b/Source/Core/VideoCommon/VideoCommon.h @@ -55,6 +55,8 @@ struct TargetRectangle : public MathUtil::Rectangle return (RECT*)this; } #endif + TargetRectangle(const MathUtil::Rectangle& other) : MathUtil::Rectangle(other) {} + TargetRectangle() = default; }; #ifdef _WIN32 diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index d8c43256e1..6bdd57a9fd 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -180,4 +180,4 @@ - + \ No newline at end of file diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index 8e5b9fef31..815fd86bbb 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -173,6 +173,9 @@ Base + + Base + Shader Generators @@ -344,6 +347,9 @@ Base + + Base + Util @@ -360,4 +366,4 @@ - + \ No newline at end of file diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 5dbc3ef196..1f6e5a38c7 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -67,8 +67,6 @@ void VideoConfig::Refresh() else iAspectRatio = aspect_ratio; bCrop = Config::Get(Config::GFX_CROP); - bUseXFB = Config::Get(Config::GFX_USE_XFB); - bUseRealXFB = Config::Get(Config::GFX_USE_REAL_XFB); iSafeTextureCache_ColorSamples = Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES); bShowFPS = Config::Get(Config::GFX_SHOW_FPS); bShowNetPlayPing = Config::Get(Config::GFX_SHOW_NETPLAY_PING); @@ -81,6 +79,7 @@ void VideoConfig::Refresh() bConvertHiresTextures = Config::Get(Config::GFX_CONVERT_HIRES_TEXTURES); bCacheHiresTextures = Config::Get(Config::GFX_CACHE_HIRES_TEXTURES); bDumpEFBTarget = Config::Get(Config::GFX_DUMP_EFB_TARGET); + bDumpXFBTarget = Config::Get(Config::GFX_DUMP_XFB_TARGET); bDumpFramesAsImages = Config::Get(Config::GFX_DUMP_FRAMES_AS_IMAGES); bFreeLook = Config::Get(Config::GFX_FREE_LOOK); bUseFFV1 = Config::Get(Config::GFX_USE_FFV1); @@ -137,6 +136,8 @@ void VideoConfig::Refresh() Config::Get(Config::GFX_HACK_BBOX_PREFER_STENCIL_IMPLEMENTATION); bForceProgressive = Config::Get(Config::GFX_HACK_FORCE_PROGRESSIVE); bSkipEFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM); + bSkipXFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM); + bImmediateXFB = Config::Get(Config::GFX_HACK_IMMEDIATE_XFB); bCopyEFBScaled = Config::Get(Config::GFX_HACK_COPY_EFB_ENABLED); bEFBEmulateFormatChanges = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES); bVertexRounding = Config::Get(Config::GFX_HACK_VERTEX_ROUDING); @@ -170,13 +171,6 @@ void VideoConfig::VerifyValidity() 10000); iStereoMode = 0; } - - if (bUseXFB && bUseRealXFB) - { - OSD::AddMessage("Stereoscopic 3D isn't supported with Real XFB, turning off stereoscopy.", - 10000); - iStereoMode = 0; - } } } diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index c49fe90456..03f8a7368c 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -65,8 +65,6 @@ struct VideoConfig final bool bWidescreenHack; int iAspectRatio; bool bCrop; // Aspect ratio controls. - bool bUseXFB; - bool bUseRealXFB; bool bShaderCache; // Enhancements @@ -98,6 +96,7 @@ struct VideoConfig final bool bConvertHiresTextures; bool bCacheHiresTextures; bool bDumpEFBTarget; + bool bDumpXFBTarget; bool bDumpFramesAsImages; bool bUseFFV1; std::string sDumpCodec; @@ -118,6 +117,8 @@ struct VideoConfig final bool bEFBEmulateFormatChanges; bool bSkipEFBCopyToRam; + bool bSkipXFBCopyToRam; + bool bImmediateXFB; bool bCopyEFBScaled; int iSafeTextureCache_ColorSamples; ProjectionHackConfig phack; @@ -221,14 +222,14 @@ struct VideoConfig final bool bSupportsInternalResolutionFrameDumps; bool bSupportsGPUTextureDecoding; bool bSupportsST3CTextures; + bool bSupportsCopyToVram; + bool bForceCopyToRam; // Needed by Software Renderer bool bSupportsBitfield; // Needed by UberShaders, so must stay in VideoCommon bool bSupportsDynamicSamplerIndexing; // Needed by UberShaders, so must stay in VideoCommon bool bSupportsBPTCTextures; } backend_info; // Utility - bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; } - bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; } bool MultisamplingEnabled() const { return iMultisamples > 1; } bool ExclusiveFullscreenEnabled() const {