diff --git a/Data/Sys/GameSettings/DD2.ini b/Data/Sys/GameSettings/DD2.ini
index 23e3a0d690..3c7604df7f 100644
--- a/Data/Sys/GameSettings/DD2.ini
+++ b/Data/Sys/GameSettings/DD2.ini
@@ -18,7 +18,6 @@ EmulationIssues =
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 512
[Video_Enhancements]
diff --git a/Data/Sys/GameSettings/G8M.ini b/Data/Sys/GameSettings/G8M.ini
index 7e5e09f755..fdec5667ec 100644
--- a/Data/Sys/GameSettings/G8M.ini
+++ b/Data/Sys/GameSettings/G8M.ini
@@ -21,8 +21,5 @@ EmulationIssues = Needs Efb to Ram for BBox (proper graphics).
EFBToTextureEnable = False
BBoxEnable = True
-[Video_Settings]
-EFBScale = -1
-
[Video_Stereoscopy]
StereoConvergence = 545
diff --git a/Data/Sys/GameSettings/GAL.ini b/Data/Sys/GameSettings/GAL.ini
index 54d5b0abc2..5937932868 100644
--- a/Data/Sys/GameSettings/GAL.ini
+++ b/Data/Sys/GameSettings/GAL.ini
@@ -17,8 +17,5 @@ EmulationIssues =
[ActionReplay]
# Add action replay cheats here.
-[Video_Settings]
-EFBScale = -1
-
[Video_Stereoscopy]
StereoConvergence = 64
diff --git a/Data/Sys/GameSettings/GC6.ini b/Data/Sys/GameSettings/GC6.ini
index 78f91c156f..3fda199f82 100644
--- a/Data/Sys/GameSettings/GC6.ini
+++ b/Data/Sys/GameSettings/GC6.ini
@@ -6,7 +6,7 @@
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 4
-EmulationIssues = If EFB scale is not integral, serious texture glitches occur.
+EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
@@ -18,7 +18,4 @@ EmulationIssues = If EFB scale is not integral, serious texture glitches occur.
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
-
SafeTextureCacheColorSamples = 0
-
diff --git a/Data/Sys/GameSettings/GEO.ini b/Data/Sys/GameSettings/GEO.ini
index 6c08f8c96a..d5500775e1 100644
--- a/Data/Sys/GameSettings/GEO.ini
+++ b/Data/Sys/GameSettings/GEO.ini
@@ -21,4 +21,3 @@ EmulationIssues =
UseXFB = True
UseRealXFB = False
SafeTextureCacheColorSamples = 512
-EFBScale = -1
diff --git a/Data/Sys/GameSettings/GF7.ini b/Data/Sys/GameSettings/GF7.ini
index 9dbaeb7699..f55343120d 100644
--- a/Data/Sys/GameSettings/GF7.ini
+++ b/Data/Sys/GameSettings/GF7.ini
@@ -7,7 +7,7 @@ FPRF = True
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 4
-EmulationIssues = EFB must be an integer (integral, 1x, 2x, 3x).
+EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
@@ -19,8 +19,6 @@ EmulationIssues = EFB must be an integer (integral, 1x, 2x, 3x).
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
-
SafeTextureCacheColorSamples = 512
[Video_Hacks]
diff --git a/Data/Sys/GameSettings/GWO.ini b/Data/Sys/GameSettings/GWO.ini
index d77ef3759f..c7969716af 100644
--- a/Data/Sys/GameSettings/GWO.ini
+++ b/Data/Sys/GameSettings/GWO.ini
@@ -16,7 +16,3 @@ EmulationIssues =
[ActionReplay]
# Add action replay cheats here.
-
-[Video_Settings]
-EFBScale = -1
-
diff --git a/Data/Sys/GameSettings/GXX.ini b/Data/Sys/GameSettings/GXX.ini
index 4a7f22c627..7a14795c7b 100644
--- a/Data/Sys/GameSettings/GXX.ini
+++ b/Data/Sys/GameSettings/GXX.ini
@@ -7,7 +7,7 @@ SyncGPU = True
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 4
-EmulationIssues = HLE music fades in and out. If EFB scale is not integral, 1x, 2x or 3x serious texture glitches occur
+EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
@@ -19,5 +19,4 @@ EmulationIssues = HLE music fades in and out. If EFB scale is not integral, 1x,
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 0
diff --git a/Data/Sys/GameSettings/GZW.ini b/Data/Sys/GameSettings/GZW.ini
index 7600ef7c8c..af37310369 100644
--- a/Data/Sys/GameSettings/GZW.ini
+++ b/Data/Sys/GameSettings/GZW.ini
@@ -19,7 +19,6 @@ EmulationIssues =
[Video_Settings]
SafeTextureCacheColorSamples = 512
-EFBScale = -1
[Video_Enhancements]
ForceFiltering = False
diff --git a/Data/Sys/GameSettings/RFF.ini b/Data/Sys/GameSettings/RFF.ini
index 373b4eb202..f11cb7af29 100644
--- a/Data/Sys/GameSettings/RFF.ini
+++ b/Data/Sys/GameSettings/RFF.ini
@@ -6,7 +6,7 @@
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 4
-EmulationIssues = Needs integral scaling for the black lines to disappear.
+EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
@@ -18,6 +18,4 @@ EmulationIssues = Needs integral scaling for the black lines to disappear.
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 512
-
diff --git a/Data/Sys/GameSettings/RPO.ini b/Data/Sys/GameSettings/RPO.ini
index 36cfa915ae..10017d90c6 100644
--- a/Data/Sys/GameSettings/RPO.ini
+++ b/Data/Sys/GameSettings/RPO.ini
@@ -18,5 +18,4 @@ EmulationIssues = Jerky videos need safe cache.
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 512
diff --git a/Data/Sys/GameSettings/RSF.ini b/Data/Sys/GameSettings/RSF.ini
index fe36d67d32..0887f282b3 100644
--- a/Data/Sys/GameSettings/RSF.ini
+++ b/Data/Sys/GameSettings/RSF.ini
@@ -16,7 +16,3 @@ EmulationIssues =
[ActionReplay]
# Add action replay cheats here.
-
-[Video_Settings]
-EFBScale = -1
-
diff --git a/Data/Sys/GameSettings/S2E.ini b/Data/Sys/GameSettings/S2E.ini
index 060a4b7ee0..703cdfcba0 100644
--- a/Data/Sys/GameSettings/S2E.ini
+++ b/Data/Sys/GameSettings/S2E.ini
@@ -17,9 +17,6 @@ EmulationIssues = USB Microphone not emulated
[ActionReplay]
# Add action replay cheats here.
-[Video_Settings]
-EFBScale = -1
-
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False
diff --git a/Data/Sys/GameSettings/S72.ini b/Data/Sys/GameSettings/S72.ini
index f2546f3bde..c45eb5a443 100644
--- a/Data/Sys/GameSettings/S72.ini
+++ b/Data/Sys/GameSettings/S72.ini
@@ -21,7 +21,6 @@ EmulationIssues =
UseXFB = True
UseRealXFB = False
SafeTextureCacheColorSamples = 0
-EFBScale = -1
[Video_Hacks]
EFBToTextureEnable = False
diff --git a/Data/Sys/GameSettings/S75.ini b/Data/Sys/GameSettings/S75.ini
index 60054e0583..07f580e342 100644
--- a/Data/Sys/GameSettings/S75.ini
+++ b/Data/Sys/GameSettings/S75.ini
@@ -5,8 +5,8 @@
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
-EmulationIssues = Skip any errors at startup and use integral efb scale.
EmulationStateId = 4
+EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
@@ -18,6 +18,4 @@ EmulationStateId = 4
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 512
-
diff --git a/Data/Sys/GameSettings/SD2.ini b/Data/Sys/GameSettings/SD2.ini
index ca3131638b..c21ea2741a 100644
--- a/Data/Sys/GameSettings/SD2.ini
+++ b/Data/Sys/GameSettings/SD2.ini
@@ -18,7 +18,6 @@ EmulationIssues =
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 512
[Video_Enhancements]
diff --git a/Data/Sys/GameSettings/SD2J01.ini b/Data/Sys/GameSettings/SD2J01.ini
index 608458a95f..42dd4a827d 100644
--- a/Data/Sys/GameSettings/SD2J01.ini
+++ b/Data/Sys/GameSettings/SD2J01.ini
@@ -21,7 +21,6 @@ EmulationIssues =
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 512
[Video_Enhancements]
diff --git a/Data/Sys/GameSettings/SDN.ini b/Data/Sys/GameSettings/SDN.ini
index 65d96bed93..ac1f84d08d 100644
--- a/Data/Sys/GameSettings/SDN.ini
+++ b/Data/Sys/GameSettings/SDN.ini
@@ -17,9 +17,6 @@ EmulationIssues =
[ActionReplay]
# Add action replay cheats here.
-[Video_Settings]
-EFBScale = -1
-
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False
diff --git a/Data/Sys/GameSettings/SEM.ini b/Data/Sys/GameSettings/SEM.ini
index 25df25a90e..c713fb992e 100644
--- a/Data/Sys/GameSettings/SEM.ini
+++ b/Data/Sys/GameSettings/SEM.ini
@@ -18,7 +18,6 @@ EmulationIssues = Enable progressive scan if the game has boot issues.
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 0
[Video_Enhancements]
diff --git a/Data/Sys/GameSettings/SER.ini b/Data/Sys/GameSettings/SER.ini
index 72b3e478bc..12eba20732 100644
--- a/Data/Sys/GameSettings/SER.ini
+++ b/Data/Sys/GameSettings/SER.ini
@@ -18,6 +18,5 @@ EmulationIssues = Enable progressive scan if the game has boot issues.
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 0
diff --git a/Data/Sys/GameSettings/SJD.ini b/Data/Sys/GameSettings/SJD.ini
index 0fa1832bb7..18a60ae328 100644
--- a/Data/Sys/GameSettings/SJD.ini
+++ b/Data/Sys/GameSettings/SJD.ini
@@ -18,7 +18,6 @@ EmulationIssues =
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 512
[Video_Enhancements]
diff --git a/Data/Sys/GameSettings/SJDJ01.ini b/Data/Sys/GameSettings/SJDJ01.ini
index 365cea7464..835937ef6d 100644
--- a/Data/Sys/GameSettings/SJDJ01.ini
+++ b/Data/Sys/GameSettings/SJDJ01.ini
@@ -21,7 +21,6 @@ EmulationIssues =
# Add action replay cheats here.
[Video_Settings]
-EFBScale = -1
SafeTextureCacheColorSamples = 512
[Video_Enhancements]
diff --git a/Data/Sys/GameSettings/SJX.ini b/Data/Sys/GameSettings/SJX.ini
index ebbdf2754e..a1ea51ac80 100644
--- a/Data/Sys/GameSettings/SJX.ini
+++ b/Data/Sys/GameSettings/SJX.ini
@@ -17,9 +17,6 @@ EmulationIssues =
[ActionReplay]
# Add action replay cheats here.
-[Video_Settings]
-EFBScale = -1
-
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False
diff --git a/Data/Sys/GameSettings/SMO.ini b/Data/Sys/GameSettings/SMO.ini
index 45625a3be7..a5f7ce214b 100644
--- a/Data/Sys/GameSettings/SMO.ini
+++ b/Data/Sys/GameSettings/SMO.ini
@@ -17,9 +17,6 @@ EmulationIssues =
[ActionReplay]
# Add action replay cheats here.
-[Video_Settings]
-EFBScale = -1
-
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False
diff --git a/Data/Sys/GameSettings/SNC.ini b/Data/Sys/GameSettings/SNC.ini
index 3819a268d2..0082c8fcf6 100644
--- a/Data/Sys/GameSettings/SNC.ini
+++ b/Data/Sys/GameSettings/SNC.ini
@@ -17,9 +17,6 @@ EmulationStateId = 5
[ActionReplay]
# Add action replay cheats here.
-[Video_Settings]
-EFBScale = -1
-
[Video_Hacks]
EFBAccessEnable = False
diff --git a/Data/Sys/GameSettings/WR9.ini b/Data/Sys/GameSettings/WR9.ini
index 7e619cdfe0..2323587565 100644
--- a/Data/Sys/GameSettings/WR9.ini
+++ b/Data/Sys/GameSettings/WR9.ini
@@ -20,7 +20,5 @@ EmulationIssues =
[Video_Settings]
UseXFB = True
UseRealXFB = False
-EFBScale = -1
-
SafeTextureCacheColorSamples = 512
diff --git a/Data/Sys/GameSettings/WRX.ini b/Data/Sys/GameSettings/WRX.ini
index 4af637d7cc..08fdc132de 100644
--- a/Data/Sys/GameSettings/WRX.ini
+++ b/Data/Sys/GameSettings/WRX.ini
@@ -20,7 +20,4 @@ EmulationIssues =
[Video_Settings]
UseXFB = True
UseRealXFB = False
-
SafeTextureCacheColorSamples = 512
-EFBScale = -1
-
diff --git a/Source/Android/app/src/main/res/values/arrays.xml b/Source/Android/app/src/main/res/values/arrays.xml
index deeba91df3..aa5d87486e 100644
--- a/Source/Android/app/src/main/res/values/arrays.xml
+++ b/Source/Android/app/src/main/res/values/arrays.xml
@@ -104,9 +104,7 @@
- 1x Native (640x528)
- - 1.5x Native (960x792)
- 2x Native (1280x1056) for 720p
- - 2.5x Native (1600x1320)
- 3x Native (1920x1584) for 1080p
- 4x Native (2560x2112)
- 5x Native (3200x2640)
@@ -114,9 +112,7 @@
- 2
- - 3
- 4
- - 5
- 6
- 7
- 8
diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp
index 205fdff401..11dc72f3fc 100644
--- a/Source/Core/Core/Config/GraphicsSettings.cpp
+++ b/Source/Core/Core/Config/GraphicsSettings.cpp
@@ -4,13 +4,48 @@
#include "Core/Config/GraphicsSettings.h"
+#include
#include
#include "Common/Config/Config.h"
+#include "Common/StringUtil.h"
#include "VideoCommon/VideoConfig.h"
namespace Config
{
+std::optional ConvertFromLegacyEFBScale(int efb_scale)
+{
+ // In game INIs, -1 was used as a special value meaning
+ // "use the value from the base layer but round it to an integer scale".
+ // We only support integer scales nowadays, so we can simply ignore -1
+ // in game INIs in order to automatically use a previous layer's value.
+ if (efb_scale < 0)
+ return {};
+
+ return efb_scale - (efb_scale > 0) - (efb_scale > 2) - (efb_scale > 4);
+}
+
+std::optional ConvertFromLegacyEFBScale(const std::string& efb_scale)
+{
+ int efb_scale_int;
+ if (!TryParse(efb_scale, &efb_scale_int))
+ return {};
+ return ConvertFromLegacyEFBScale(efb_scale_int);
+}
+
+int ConvertToLegacyEFBScale(int efb_scale)
+{
+ return efb_scale + (efb_scale >= 0) + (efb_scale > 1) + (efb_scale > 2);
+}
+
+std::optional ConvertToLegacyEFBScale(const std::string& efb_scale)
+{
+ int efb_scale_int;
+ if (!TryParse(efb_scale, &efb_scale_int))
+ return {};
+ return ConvertToLegacyEFBScale(efb_scale_int);
+}
+
// Configuration Information
// Graphics.Hardware
@@ -60,8 +95,7 @@ const ConfigInfo GFX_ENABLE_PIXEL_LIGHTING{{System::GFX, "Settings", "Enab
const ConfigInfo GFX_FAST_DEPTH_CALC{{System::GFX, "Settings", "FastDepthCalc"}, true};
const ConfigInfo GFX_MSAA{{System::GFX, "Settings", "MSAA"}, 1};
const ConfigInfo GFX_SSAA{{System::GFX, "Settings", "SSAA"}, false};
-const ConfigInfo GFX_EFB_SCALE{{System::GFX, "Settings", "EFBScale"},
- static_cast(SCALE_1X)};
+const ConfigInfo GFX_EFB_SCALE{{System::GFX, "Settings", "EFBScale"}, 1};
const ConfigInfo GFX_TEXFMT_OVERLAY_ENABLE{{System::GFX, "Settings", "TexFmtOverlayEnable"},
false};
const ConfigInfo GFX_TEXFMT_OVERLAY_CENTER{{System::GFX, "Settings", "TexFmtOverlayCenter"},
diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h
index 046675d058..b1ec5c1dac 100644
--- a/Source/Core/Core/Config/GraphicsSettings.h
+++ b/Source/Core/Core/Config/GraphicsSettings.h
@@ -4,12 +4,18 @@
#pragma once
+#include
#include
#include "Common/Config/Config.h"
namespace Config
{
+std::optional ConvertFromLegacyEFBScale(int efb_scale);
+std::optional ConvertFromLegacyEFBScale(const std::string& efb_scale);
+int ConvertToLegacyEFBScale(int efb_scale);
+std::optional ConvertToLegacyEFBScale(const std::string& efb_scale);
+
// Configuration Information
// Graphics.Hardware
diff --git a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp
index 72e86a4a1f..89850b49dd 100644
--- a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp
+++ b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp
@@ -17,6 +17,7 @@
#include "Common/Logging/Log.h"
#include "Common/Config/Config.h"
+#include "Core/Config/GraphicsSettings.h"
#include "Core/ConfigLoaders/IsSettingSaveable.h"
namespace ConfigLoaders
@@ -53,7 +54,19 @@ public:
const IniFile::Section::SectionMap& section_map = section.GetValues();
for (const auto& value : section_map)
- config_section->Set(value.first, value.second);
+ {
+ const Config::ConfigLocation location{system.first, section_name, value.first};
+ if (location == Config::GFX_EFB_SCALE.location)
+ {
+ std::optional efb_scale = Config::ConvertFromLegacyEFBScale(value.second);
+ if (efb_scale)
+ config_section->Set(value.first, *efb_scale);
+ }
+ else
+ {
+ config_section->Set(value.first, value.second);
+ }
+ }
}
}
}
@@ -83,10 +96,20 @@ public:
for (const auto& value : section_values)
{
- if (!IsSettingSaveable({system.first, section->GetName(), value.first}))
+ const Config::ConfigLocation location{system.first, section->GetName(), value.first};
+ if (!IsSettingSaveable(location))
continue;
- ini_section->Set(value.first, value.second);
+ if (location == Config::GFX_EFB_SCALE.location)
+ {
+ std::optional efb_scale = Config::ConvertToLegacyEFBScale(value.second);
+ if (efb_scale)
+ ini_section->Set(value.first, *efb_scale);
+ }
+ else
+ {
+ ini_section->Set(value.first, value.second);
+ }
}
}
diff --git a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp
index 84b6f41267..eb36f761f2 100644
--- a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp
+++ b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp
@@ -312,7 +312,17 @@ private:
auto* config_section =
config_layer->GetOrCreateSection(mapped_config.system, mapped_config.section);
- config_section->Set(mapped_config.key, value.second);
+
+ if (mapped_config == Config::GFX_EFB_SCALE.location)
+ {
+ std::optional efb_scale = Config::ConvertFromLegacyEFBScale(value.second);
+ if (efb_scale)
+ config_section->Set(mapped_config.key, *efb_scale);
+ }
+ else
+ {
+ config_section->Set(mapped_config.key, value.second);
+ }
}
}
@@ -335,16 +345,25 @@ void INIGameConfigLayerLoader::Save(Config::Layer* config_layer)
{
for (const auto& value : section->GetValues())
{
- if (!IsSettingSaveable({system.first, section->GetName(), value.first}))
+ const Config::ConfigLocation location{system.first, section->GetName(), value.first};
+ if (!IsSettingSaveable(location))
continue;
- const auto ini_location =
- GetINILocationFromConfig({system.first, section->GetName(), value.first});
+ const auto ini_location = GetINILocationFromConfig(location);
if (ini_location.first.empty() && ini_location.second.empty())
continue;
IniFile::Section* ini_section = ini.GetOrCreateSection(ini_location.first);
- ini_section->Set(ini_location.second, value.second);
+ if (location == Config::GFX_EFB_SCALE.location)
+ {
+ std::optional efb_scale = Config::ConvertToLegacyEFBScale(value.second);
+ if (efb_scale)
+ ini_section->Set(ini_location.second, *efb_scale);
+ }
+ else
+ {
+ ini_section->Set(ini_location.second, value.second);
+ }
}
}
}
diff --git a/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.cpp b/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.cpp
index 3377c51de1..cb4b021760 100644
--- a/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.cpp
+++ b/Source/Core/DolphinQt2/Config/Graphics/EnhancementsWidget.cpp
@@ -43,16 +43,15 @@ void EnhancementsWidget::CreateWidgets()
auto* enhancements_layout = new QGridLayout();
enhancements_box->setLayout(enhancements_layout);
- m_ir_combo = new GraphicsChoice(
- {tr("Auto (Window Size)"), tr("Auto (Multiple of 640x528)"), tr("Native (640x528)"),
- tr("1.5x Native (960x792)"), tr("2x Native (1280x1056) for 720p"),
- tr("2.5x Native (1600x1320)"), tr("3x Native (1920x1584) for 1080p"),
- tr("4x Native (2560x2112) for 1440p"), tr("5x Native (3200x2640)"),
- tr("6x Native (3840x3168) for 4K"), tr("7x Native (4480x3696)"),
- tr("8x Native (5120x4224) for 5K")},
- Config::GFX_EFB_SCALE);
+ m_ir_combo = new GraphicsChoice({tr("Auto (Multiple of 640x528)"), tr("Native (640x528)"),
+ tr("2x Native (1280x1056) for 720p"),
+ tr("3x Native (1920x1584) for 1080p"),
+ tr("4x Native (2560x2112) for 1440p"),
+ tr("5x Native (3200x2640)"), tr("6x Native (3840x3168) for 4K"),
+ tr("7x Native (4480x3696)"), tr("8x Native (5120x4224) for 5K")},
+ Config::GFX_EFB_SCALE);
- if (g_Config.iEFBScale > 11)
+ if (g_Config.iEFBScale > 8)
{
m_ir_combo->addItem(tr("Custom"));
m_ir_combo->setCurrentIndex(m_ir_combo->count() - 1);
@@ -221,10 +220,8 @@ void EnhancementsWidget::AddDescriptions()
static const char* TR_INTERNAL_RESOLUTION_DESCRIPTION =
QT_TR_NOOP("Specifies the resolution used to render at. A high resolution greatly improves "
"visual quality, but also greatly increases GPU load and can cause issues in "
- "certain games.\n\"Multiple of 640x528\" will result in a size slightly larger "
- "than \"Window Size\" but yield fewer issues. Generally speaking, the lower the "
- "internal resolution is, the better your performance will be. Auto (Window Size), "
- "1.5x, and 2.5x may cause issues in some games.\n\nIf unsure, select Native.");
+ "certain games. Generally speaking, the lower the internal resolution is, the "
+ "better your performance will be.\n\nIf unsure, select Native.");
static const char* TR_ANTIALIAS_DESCRIPTION =
QT_TR_NOOP("Reduces the amount of aliasing caused by rasterizing 3D graphics. This smooths "
diff --git a/Source/Core/DolphinQt2/HotkeyScheduler.cpp b/Source/Core/DolphinQt2/HotkeyScheduler.cpp
index f69ac1b257..e938663826 100644
--- a/Source/Core/DolphinQt2/HotkeyScheduler.cpp
+++ b/Source/Core/DolphinQt2/HotkeyScheduler.cpp
@@ -207,7 +207,7 @@ void HotkeyScheduler::Run()
if (IsHotkey(HK_INCREASE_IR))
++g_Config.iEFBScale;
if (IsHotkey(HK_DECREASE_IR))
- g_Config.iEFBScale = std::max(g_Config.iEFBScale - 1, static_cast(SCALE_AUTO));
+ g_Config.iEFBScale = std::max(g_Config.iEFBScale - 1, EFB_SCALE_AUTO_INTEGRAL);
if (IsHotkey(HK_TOGGLE_CROP))
g_Config.bCrop = !g_Config.bCrop;
if (IsHotkey(HK_TOGGLE_AR))
diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp
index 08bbcc4a52..ba689ac063 100644
--- a/Source/Core/DolphinWX/Frame.cpp
+++ b/Source/Core/DolphinWX/Frame.cpp
@@ -1446,7 +1446,7 @@ void CFrame::ParseHotkeys()
if (IsHotkey(HK_DECREASE_IR))
{
OSDChoice = 1;
- if (Config::Get(Config::GFX_EFB_SCALE) > SCALE_AUTO)
+ if (Config::Get(Config::GFX_EFB_SCALE) > EFB_SCALE_AUTO_INTEGRAL)
Config::SetCurrent(Config::GFX_EFB_SCALE, Config::Get(Config::GFX_EFB_SCALE) - 1);
}
if (IsHotkey(HK_TOGGLE_CROP))
diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp
index 4ced1d69ae..54402a5af5 100644
--- a/Source/Core/DolphinWX/VideoConfigDiag.cpp
+++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp
@@ -186,10 +186,8 @@ static wxString borderless_fullscreen_desc = wxTRANSLATE(
static wxString internal_res_desc =
wxTRANSLATE("Specifies the resolution used to render at. A high resolution greatly improves "
"visual quality, but also greatly increases GPU load and can cause issues in "
- "certain games.\n\"Multiple of 640x528\" will result in a size slightly larger "
- "than \"Window Size\" but yield fewer issues. Generally speaking, the lower the "
- "internal resolution is, the better your performance will be. Auto (Window Size), "
- "1.5x, and 2.5x may cause issues in some games.\n\nIf unsure, select Native.");
+ "certain games. Generally speaking, the lower the internal resolution is, the "
+ "better your performance will be.\n\nIf unsure, select Native.");
static wxString efb_access_desc =
wxTRANSLATE("Ignore any requests from the CPU to read from or write to the EFB.\nImproves "
"performance in some games, but might disable some gameplay-related features or "
@@ -517,27 +515,20 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
// Internal resolution
{
- const wxString efbscale_choices[] = {_("Auto (Window Size)"),
- _("Auto (Multiple of 640x528)"),
- _("Native (640x528)"),
- _("1.5x Native (960x792)"),
- _("2x Native (1280x1056) for 720p"),
- _("2.5x Native (1600x1320)"),
- _("3x Native (1920x1584) for 1080p"),
- _("4x Native (2560x2112) for 1440p"),
- _("5x Native (3200x2640)"),
- _("6x Native (3840x3168) for 4K"),
- _("7x Native (4480x3696)"),
- _("8x Native (5120x4224) for 5K"),
- _("Custom")};
+ const wxString efbscale_choices[] = {
+ _("Auto (Multiple of 640x528)"), _("Native (640x528)"),
+ _("2x Native (1280x1056) for 720p"), _("3x Native (1920x1584) for 1080p"),
+ _("4x Native (2560x2112) for 1440p"), _("5x Native (3200x2640)"),
+ _("6x Native (3840x3168) for 4K"), _("7x Native (4480x3696)"),
+ _("8x Native (5120x4224) for 5K"), _("Custom")};
wxChoice* const choice_efbscale = CreateChoice(
page_enh, Config::GFX_EFB_SCALE, wxGetTranslation(internal_res_desc),
- (vconfig.iEFBScale > 11) ? ArraySize(efbscale_choices) : ArraySize(efbscale_choices) - 1,
+ (vconfig.iEFBScale > 8) ? ArraySize(efbscale_choices) : ArraySize(efbscale_choices) - 1,
efbscale_choices);
- if (vconfig.iEFBScale > 11)
- choice_efbscale->SetSelection(12);
+ if (vconfig.iEFBScale > 8)
+ choice_efbscale->SetSelection(9);
szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Internal Resolution:")),
wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
@@ -1120,7 +1111,7 @@ void VideoConfigDiag::OnUpdateUI(wxUpdateUIEvent& ev)
cache_hires_textures->Enable(vconfig.bHiresTextures);
// Vertex rounding
- vertex_rounding_checkbox->Enable(vconfig.iEFBScale != SCALE_1X);
+ vertex_rounding_checkbox->Enable(vconfig.iEFBScale != 1);
// Repopulating the post-processing shaders can't be done from an event
if (choice_ppshader && choice_ppshader->IsEmpty())
diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp
index 51a7dfda08..b89e812879 100644
--- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp
+++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp
@@ -128,10 +128,10 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w
D3D::stateman->SetPixelConstants(m_encodeParams);
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
- // TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will
- // need more complex down filtering to average all pixels and produce the correct result.
+ // 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_ActiveConfig.iEFBScale != SCALE_1X)
+ if (scale_by_half || g_ActiveConfig.iEFBScale != 1)
D3D::SetLinearCopySampler();
else
D3D::SetPointCopySampler();
diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/TextureConverter.cpp
index e9a3eaa94f..6c438b6a1f 100644
--- a/Source/Core/VideoBackends/OGL/TextureConverter.cpp
+++ b/Source/Core/VideoBackends/OGL/TextureConverter.cpp
@@ -230,10 +230,10 @@ static void EncodeToRamUsingShader(GLuint srcTexture, u8* destAddr, u32 dst_line
glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture);
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
- // TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will
- // need more complex down filtering to average all pixels and produce the correct result.
+ // 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_ActiveConfig.iEFBScale != SCALE_1X)
+ if (linearFilter || g_ActiveConfig.iEFBScale != 1)
g_sampler_cache->BindLinearSampler(9);
else
g_sampler_cache->BindNearestSampler(9);
diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
index 20be913b6a..15d0ae7572 100644
--- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
+++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp
@@ -248,9 +248,9 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
draw.SetPushConstants(position_uniform, sizeof(position_uniform));
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
- // TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will
- // need more complex down filtering to average all pixels and produce the correct result.
- bool linear_filter = (scale_by_half && !params.depth) || g_ActiveConfig.iEFBScale != SCALE_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_ActiveConfig.iEFBScale != 1;
draw.SetPSSampler(0, src_texture, linear_filter ? g_object_cache->GetLinearSampler() :
g_object_cache->GetPointSampler());
diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp
index 9f425e4cd2..36297ed53e 100644
--- a/Source/Core/VideoCommon/RenderBase.cpp
+++ b/Source/Core/VideoCommon/RenderBase.cpp
@@ -80,8 +80,7 @@ static float AspectToWidescreen(float aspect)
}
Renderer::Renderer(int backbuffer_width, int backbuffer_height)
- : m_backbuffer_width(backbuffer_width), m_backbuffer_height(backbuffer_height),
- m_last_efb_scale(g_ActiveConfig.iEFBScale)
+ : m_backbuffer_width(backbuffer_width), m_backbuffer_height(backbuffer_height)
{
FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
@@ -134,26 +133,12 @@ void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStri
int Renderer::EFBToScaledX(int x) const
{
- switch (g_ActiveConfig.iEFBScale)
- {
- case SCALE_AUTO: // fractional
- return FramebufferManagerBase::ScaleToVirtualXfbWidth(x, m_target_rectangle);
-
- default:
- return x * (int)m_efb_scale_numeratorX / (int)m_efb_scale_denominatorX;
- };
+ return x * static_cast(m_efb_scale);
}
int Renderer::EFBToScaledY(int y) const
{
- switch (g_ActiveConfig.iEFBScale)
- {
- case SCALE_AUTO: // fractional
- return FramebufferManagerBase::ScaleToVirtualXfbHeight(y, m_target_rectangle);
-
- default:
- return y * (int)m_efb_scale_numeratorY / (int)m_efb_scale_denominatorY;
- };
+ return y * static_cast(m_efb_scale);
}
float Renderer::EFBToScaledXf(float x) const
@@ -168,89 +153,31 @@ float Renderer::EFBToScaledYf(float y) const
std::tuple Renderer::CalculateTargetScale(int x, int y) const
{
- if (g_ActiveConfig.iEFBScale == SCALE_AUTO || g_ActiveConfig.iEFBScale == SCALE_AUTO_INTEGRAL)
- {
- return std::make_tuple(x, y);
- }
-
- const int scaled_x =
- x * static_cast(m_efb_scale_numeratorX) / static_cast(m_efb_scale_denominatorX);
-
- const int scaled_y =
- y * static_cast(m_efb_scale_numeratorY) / static_cast(m_efb_scale_denominatorY);
-
- return std::make_tuple(scaled_x, scaled_y);
+ return std::make_tuple(x * static_cast(m_efb_scale), y * static_cast(m_efb_scale));
}
// return true if target size changed
bool Renderer::CalculateTargetSize()
{
- m_last_efb_scale = g_ActiveConfig.iEFBScale;
+ 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);
+ m_efb_scale = std::max((width - 1) / EFB_WIDTH + 1, (height - 1) / EFB_HEIGHT + 1);
+ }
+ else
+ {
+ m_efb_scale = g_ActiveConfig.iEFBScale;
+ }
+
+ const u32 max_size = g_ActiveConfig.backend_info.MaxTextureSize;
+ if (max_size < EFB_WIDTH * m_efb_scale)
+ m_efb_scale = max_size / EFB_WIDTH;
int new_efb_width = 0;
int new_efb_height = 0;
-
- // TODO: Ugly. Clean up
- switch (m_last_efb_scale)
- {
- case SCALE_AUTO:
- case SCALE_AUTO_INTEGRAL:
- new_efb_width = FramebufferManagerBase::ScaleToVirtualXfbWidth(EFB_WIDTH, m_target_rectangle);
- new_efb_height =
- FramebufferManagerBase::ScaleToVirtualXfbHeight(EFB_HEIGHT, m_target_rectangle);
-
- if (m_last_efb_scale == SCALE_AUTO_INTEGRAL)
- {
- m_efb_scale_numeratorX = m_efb_scale_numeratorY =
- std::max((new_efb_width - 1) / EFB_WIDTH + 1, (new_efb_height - 1) / EFB_HEIGHT + 1);
- m_efb_scale_denominatorX = m_efb_scale_denominatorY = 1;
- new_efb_width = EFBToScaledX(EFB_WIDTH);
- new_efb_height = EFBToScaledY(EFB_HEIGHT);
- }
- else
- {
- m_efb_scale_numeratorX = new_efb_width;
- m_efb_scale_denominatorX = EFB_WIDTH;
- m_efb_scale_numeratorY = new_efb_height;
- m_efb_scale_denominatorY = EFB_HEIGHT;
- }
- break;
-
- case SCALE_1X:
- m_efb_scale_numeratorX = m_efb_scale_numeratorY = 1;
- m_efb_scale_denominatorX = m_efb_scale_denominatorY = 1;
- break;
-
- case SCALE_1_5X:
- m_efb_scale_numeratorX = m_efb_scale_numeratorY = 3;
- m_efb_scale_denominatorX = m_efb_scale_denominatorY = 2;
- break;
-
- case SCALE_2X:
- m_efb_scale_numeratorX = m_efb_scale_numeratorY = 2;
- m_efb_scale_denominatorX = m_efb_scale_denominatorY = 1;
- break;
-
- case SCALE_2_5X:
- m_efb_scale_numeratorX = m_efb_scale_numeratorY = 5;
- m_efb_scale_denominatorX = m_efb_scale_denominatorY = 2;
- break;
-
- default:
- m_efb_scale_numeratorX = m_efb_scale_numeratorY = m_last_efb_scale - 3;
- m_efb_scale_denominatorX = m_efb_scale_denominatorY = 1;
-
- const u32 max_size = g_ActiveConfig.backend_info.MaxTextureSize;
- if (max_size < EFB_WIDTH * m_efb_scale_numeratorX / m_efb_scale_denominatorX)
- {
- m_efb_scale_numeratorX = m_efb_scale_numeratorY = (max_size / EFB_WIDTH);
- m_efb_scale_denominatorX = m_efb_scale_denominatorY = 1;
- }
-
- break;
- }
- if (m_last_efb_scale > SCALE_AUTO_INTEGRAL)
- std::tie(new_efb_width, new_efb_height) = CalculateTargetScale(EFB_WIDTH, EFB_HEIGHT);
+ std::tie(new_efb_width, new_efb_height) = CalculateTargetScale(EFB_WIDTH, EFB_HEIGHT);
if (new_efb_width != m_target_width || new_efb_height != m_target_height)
{
@@ -383,26 +310,14 @@ void Renderer::DrawDebugText()
std::string res_text;
switch (g_ActiveConfig.iEFBScale)
{
- case SCALE_AUTO:
- res_text = "Auto (fractional)";
- break;
- case SCALE_AUTO_INTEGRAL:
+ case EFB_SCALE_AUTO_INTEGRAL:
res_text = "Auto (integral)";
break;
- case SCALE_1X:
+ case 1:
res_text = "Native";
break;
- case SCALE_1_5X:
- res_text = "1.5x";
- break;
- case SCALE_2X:
- res_text = "2x";
- break;
- case SCALE_2_5X:
- res_text = "2.5x";
- break;
default:
- res_text = StringFromFormat("%dx", g_ActiveConfig.iEFBScale - 3);
+ res_text = StringFromFormat("%dx", g_ActiveConfig.iEFBScale);
break;
}
const char* ar_text = "";
@@ -648,7 +563,8 @@ void Renderer::SetWindowSize(int width, int height)
height = std::max(height, 1);
// Scale the window size by the EFB scale.
- std::tie(width, height) = CalculateTargetScale(width, height);
+ if (g_ActiveConfig.iEFBScale != EFB_SCALE_AUTO_INTEGRAL)
+ std::tie(width, height) = CalculateTargetScale(width, height);
float scaled_width, scaled_height;
std::tie(scaled_width, scaled_height) = ScaleToDisplayAspectRatio(width, height);
diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h
index 4045b223aa..296d97bf94 100644
--- a/Source/Core/VideoCommon/RenderBase.h
+++ b/Source/Core/VideoCommon/RenderBase.h
@@ -78,8 +78,7 @@ public:
virtual void RestoreState() {}
virtual void ResetAPIState() {}
virtual void RestoreAPIState() {}
- // Ideal internal resolution - determined by display resolution (automatic scaling) and/or a
- // multiple of the native EFB resolution
+ // Ideal internal resolution - multiple of the native EFB resolution
int GetTargetWidth() const { return m_target_width; }
int GetTargetHeight() const { return m_target_height; }
// Display resolution
@@ -170,7 +169,6 @@ protected:
// TODO: Add functionality to reinit all the render targets when the window is resized.
int m_backbuffer_width = 0;
int m_backbuffer_height = 0;
- int m_last_efb_scale = 0;
TargetRectangle m_target_rectangle = {};
bool m_xfb_written = false;
@@ -191,10 +189,7 @@ private:
void ShutdownFrameDumping();
PEControl::PixelFormat m_prev_efb_format = PEControl::INVALID_FMT;
- unsigned int m_efb_scale_numeratorX = 1;
- unsigned int m_efb_scale_numeratorY = 1;
- unsigned int m_efb_scale_denominatorX = 1;
- unsigned int m_efb_scale_denominatorY = 1;
+ unsigned int m_efb_scale = 1;
// These will be set on the first call to SetWindowSize.
int m_last_window_request_width = 0;
diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp
index ad20ab2332..2d1269509d 100644
--- a/Source/Core/VideoCommon/VertexShaderManager.cpp
+++ b/Source/Core/VideoCommon/VertexShaderManager.cpp
@@ -376,8 +376,7 @@ void VertexShaderManager::SetConstants()
// NOTE: If we ever emulate antialiasing, the sample locations set by
// BP registers 0x01-0x04 need to be considered here.
const float pixel_center_correction = 7.0f / 12.0f - 0.5f;
- const bool bUseVertexRounding =
- g_ActiveConfig.bVertexRounding && g_ActiveConfig.iEFBScale != SCALE_1X;
+ const bool bUseVertexRounding = g_ActiveConfig.bVertexRounding && g_ActiveConfig.iEFBScale != 1;
const float viewport_width = bUseVertexRounding ?
(2.f * xfmem.viewport.wd) :
g_renderer->EFBToScaledXf(2.f * xfmem.viewport.wd);
diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp
index 9caab54603..abc4ef4731 100644
--- a/Source/Core/VideoCommon/VideoConfig.cpp
+++ b/Source/Core/VideoCommon/VideoConfig.cpp
@@ -139,26 +139,6 @@ void VideoConfig::Refresh()
phack.m_zfar = Config::Get(Config::GFX_PROJECTION_HACK_ZFAR);
bPerfQueriesEnable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE);
- if (iEFBScale == SCALE_FORCE_INTEGRAL)
- {
- // Round down to multiple of native IR
- switch (Config::GetBase(Config::GFX_EFB_SCALE))
- {
- case SCALE_AUTO:
- iEFBScale = SCALE_AUTO_INTEGRAL;
- break;
- case SCALE_1_5X:
- iEFBScale = SCALE_1X;
- break;
- case SCALE_2_5X:
- iEFBScale = SCALE_2X;
- break;
- default:
- iEFBScale = Config::GetBase(Config::GFX_EFB_SCALE);
- break;
- }
- }
-
VerifyValidity();
}
diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h
index 499ab1c88a..e9fcece3e8 100644
--- a/Source/Core/VideoCommon/VideoConfig.h
+++ b/Source/Core/VideoCommon/VideoConfig.h
@@ -22,6 +22,8 @@
#define CONF_SAVETARGETS 8
#define CONF_SAVESHADERS 16
+constexpr int EFB_SCALE_AUTO_INTEGRAL = 0;
+
enum AspectMode
{
ASPECT_AUTO = 0,
@@ -30,17 +32,6 @@ enum AspectMode
ASPECT_STRETCH = 3,
};
-enum EFBScale
-{
- SCALE_FORCE_INTEGRAL = -1,
- SCALE_AUTO,
- SCALE_AUTO_INTEGRAL,
- SCALE_1X,
- SCALE_1_5X,
- SCALE_2X,
- SCALE_2_5X,
-};
-
enum StereoMode
{
STEREO_OFF = 0,
@@ -252,7 +243,7 @@ struct VideoConfig final
{
return backend_info.bSupportsGPUTextureDecoding && bEnableGPUTextureDecoding;
}
- bool UseVertexRounding() const { return bVertexRounding && iEFBScale != SCALE_1X; }
+ bool UseVertexRounding() const { return bVertexRounding && iEFBScale != 1; }
u32 GetShaderCompilerThreads() const;
u32 GetShaderPrecompilerThreads() const;
bool CanPrecompileUberShaders() const;