GS: Add sharp bilinear post filter

Remove internal screenshot setting, all screenshots are internal (and it wasn't hooked up)
This commit is contained in:
refractionpcsx2 2022-11-22 14:12:06 +00:00
parent edb9a5ba3c
commit 7e66eb856c
11 changed files with 112 additions and 50 deletions

View File

@ -104,13 +104,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.fmvAspectRatio, "EmuCore/GS", "FMVAspectRatioSwitch",
Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, FMVAspectRatioSwitchType::Off);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.interlacing, "EmuCore/GS", "deinterlace_mode", DEFAULT_INTERLACE_MODE);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.bilinearFiltering, "EmuCore/GS", "linear_present", true);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.bilinearFiltering, "EmuCore/GS", "linear_present_mode", static_cast<int>(GSPostBilinearMode::BilinearSmooth));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.integerScaling, "EmuCore/GS", "IntegerScaling", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCOffsets, "EmuCore/GS", "pcrtc_offsets", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCOverscan, "EmuCore/GS", "pcrtc_overscan", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCAntiBlur, "EmuCore/GS", "pcrtc_antiblur", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.DisableInterlaceOffset, "EmuCore/GS", "disable_interlace_offset", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.internalResolutionScreenshots, "EmuCore/GS", "InternalResolutionScreenshots", false);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.zoom, "EmuCore/GS", "Zoom", 100.0f);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.stretchY, "EmuCore/GS", "StretchY", 100.0f);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropLeft, "EmuCore/GS", "CropLeft", 0);
@ -347,7 +346,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.DisableInterlaceOffset, tr("Disable Interlace Offset"), tr("Unchecked"),
tr("Disables interlacing offset which may reduce blurring in some situations."));
dialog->registerWidgetHelp(m_ui.bilinearFiltering, tr("Bilinear Filtering"), tr("Checked"),
dialog->registerWidgetHelp(m_ui.bilinearFiltering, tr("Bilinear Filtering"), tr("Bilinear (Sharp)"),
tr("Enables bilinear post processing filter. Smooths the overall picture as it is displayed on the screen. Corrects positioning between pixels."));
dialog->registerWidgetHelp(m_ui.PCRTCOffsets, tr("Screen Offsets"), tr("Unchecked"),
@ -365,9 +364,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.vsync, tr("VSync"), tr("Unchecked"),
tr("Enable this option to match PCSX2's refresh rate with your current monitor or screen. VSync is automatically disabled when it is not possible (eg. running at non-100% speed)."));
dialog->registerWidgetHelp(m_ui.internalResolutionScreenshots, tr("Internal Resolution Screenshots"), tr("Unchecked"),
tr("Saves screenshots at internal render resolution and without postprocessing. If this option is disabled, the screenshots will be taken at the window's resolution. Internal resolution screenshots can be very large at high rendering scales."));
dialog->registerWidgetHelp(m_ui.integerScaling, tr("Integer Scaling"), tr("Unchecked"),
tr("Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an integer number. May result in a sharper image in some 2D games."));
}

View File

@ -201,14 +201,14 @@
</item>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Zoom:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QSpinBox" name="zoom">
<property name="suffix">
<string>%</string>
@ -221,14 +221,14 @@
</property>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Stretch Height:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QSpinBox" name="stretchY">
<property name="suffix">
<string>%</string>
@ -241,14 +241,14 @@
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Crop:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,0,1,0,1,0,1">
<item>
<widget class="QLabel" name="label_39">
@ -320,8 +320,15 @@
</item>
</layout>
</item>
<item row="7" column="0" colspan="2">
<item row="8" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_5">
<item row="1" column="1">
<widget class="QCheckBox" name="DisableInterlaceOffset">
<property name="text">
<string>Disable Interlace Offset</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="vsync">
<property name="text">
@ -329,20 +336,6 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="bilinearFiltering">
<property name="text">
<string>Bilinear Filtering</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="internalResolutionScreenshots">
<property name="text">
<string>Internal Resolution Screenshots</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="integerScaling">
<property name="text">
@ -364,14 +357,7 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="DisableInterlaceOffset">
<property name="text">
<string>Disable Interlace Offset</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="0" column="0">
<widget class="QCheckBox" name="PCRTCAntiBlur">
<property name="text">
<string>Anti-Blur</string>
@ -383,6 +369,32 @@
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Bilinear Filtering</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="bilinearFiltering">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear (Smooth)</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear (Sharp)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="hardwareRenderingTab">

View File

@ -144,6 +144,13 @@ enum class GSInterlaceMode : u8
Count
};
enum class GSPostBilinearMode : u8
{
Off,
BilinearSmooth,
BilinearSharp,
};
// Ordering was done to keep compatibility with older ini file.
enum class BiFiltering : u8
{
@ -484,7 +491,6 @@ struct Pcsx2Config
PCRTCOffsets : 1,
PCRTCOverscan : 1,
IntegerScaling : 1,
LinearPresent : 1,
SyncToHostRefreshRate : 1,
UseDebugDevice : 1,
UseBlitSwapChain : 1,
@ -560,6 +566,7 @@ struct Pcsx2Config
AspectRatioType AspectRatio{AspectRatioType::RAuto4_3_3_2};
FMVAspectRatioSwitchType FMVAspectRatioSwitch{FMVAspectRatioSwitchType::Off};
GSInterlaceMode InterlaceMode{GSInterlaceMode::Automatic};
GSPostBilinearMode LinearPresent{ GSPostBilinearMode::BilinearSmooth };
float Zoom{100.0f};
float StretchY{100.0f};

View File

@ -2793,6 +2793,7 @@ void FullscreenUI::DrawGraphicsSettingsPage()
"11", //GSRendererType::Null
};
static constexpr const char* s_vsync_values[] = {"Off", "On", "Adaptive"};
static constexpr const char* s_bilinear_present_options[] = {"Off", "Bilinear (Smooth)", "Bilinear (Sharp)"};
static constexpr const char* s_deinterlacing_options[] = {"Automatic (Default)", "None", "Weave (Top Field First, Sawtooth)",
"Weave (Bottom Field First, Sawtooth)", "Bob (Top Field First)", "Bob (Bottom Field First)", "Blend (Top Field First, Half FPS)",
"Blend (Bottom Field First, Half FPS)", "Adaptive (Top Field First)", "Adaptive (Bottom Field First)"};
@ -2877,15 +2878,13 @@ void FullscreenUI::DrawGraphicsSettingsPage()
100, 10, 300, "%d%%");
DrawIntRectSetting(bsi, "Crop", "Crops the image, while respecting aspect ratio.", "EmuCore/GS", "CropLeft", 0, "CropTop", 0,
"CropRight", 0, "CropBottom", 0, 0, 720, "%dpx");
DrawToggleSetting(
bsi, "Bilinear Upscaling", "Smooths out the image when upscaling the console to the screen.", "EmuCore/GS", "linear_present", true);
DrawIntListSetting(bsi, "Bilinear Upscaling",
"Smooths out the image when upscaling the console to the screen.", "EmuCore/GS", "linear_present_mode",
static_cast<int>(GSPostBilinearMode::BilinearSharp), s_bilinear_present_options, std::size(s_bilinear_present_options));
DrawToggleSetting(bsi, "Integer Upscaling",
"Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an integer "
"number. May result in a sharper image in some 2D games.",
"EmuCore/GS", "IntegerScaling", false);
DrawToggleSetting(bsi, "Internal Resolution Screenshots",
"Save screenshots at the full render resolution, rather than display resolution.", "EmuCore/GS", "InternalResolutionScreenshots",
false);
DrawToggleSetting(bsi, "Screen Offsets", "Enables PCRTC Offsets which position the screen as the game requests.", "EmuCore/GS",
"pcrtc_offsets", false);
DrawToggleSetting(bsi, "Show Overscan",

View File

@ -1354,6 +1354,10 @@ void GSApp::Init()
m_gs_texture_preloading.push_back(GSSetting(static_cast<u32>(TexturePreloadingLevel::Partial), "Partial", ""));
m_gs_texture_preloading.push_back(GSSetting(static_cast<u32>(TexturePreloadingLevel::Full), "Full", "Hash Cache"));
m_gs_tex_display_list.push_back(GSSetting(static_cast<u32>(GSPostBilinearMode::Off), "None", ""));
m_gs_tex_display_list.push_back(GSSetting(static_cast<u32>(GSPostBilinearMode::BilinearSmooth), "Bilinear (Smooth)", ""));
m_gs_tex_display_list.push_back(GSSetting(static_cast<u32>(GSPostBilinearMode::BilinearSharp), "Bilinear (Sharp)", ""));
m_gs_generic_list.push_back(GSSetting(-1, "Automatic", "Default"));
m_gs_generic_list.push_back(GSSetting(0, "Force-Disabled", ""));
m_gs_generic_list.push_back(GSSetting(1, "Force-Enabled", ""));
@ -1455,7 +1459,7 @@ void GSApp::Init()
m_default_configuration["pcrtc_overscan"] = "0";
m_default_configuration["IntegerScaling"] = "0";
m_default_configuration["deinterlace_mode"] = std::to_string(static_cast<s8>(GSInterlaceMode::Automatic));
m_default_configuration["linear_present"] = "1";
m_default_configuration["linear_present_mode"] = std::to_string(static_cast<s8>(GSPostBilinearMode::BilinearSmooth));
m_default_configuration["LoadTextureReplacements"] = "0";
m_default_configuration["LoadTextureReplacementsAsync"] = "1";
m_default_configuration["MaxAnisotropy"] = "0";

View File

@ -137,6 +137,7 @@ public:
std::vector<GSSetting> m_gs_texture_preloading;
std::vector<GSSetting> m_gs_hack;
std::vector<GSSetting> m_gs_generic_list;
std::vector<GSSetting> m_gs_tex_display_list;
std::vector<GSSetting> m_gs_offset_hack;
std::vector<GSSetting> m_gs_hw_mipmapping;
std::vector<GSSetting> m_gs_crc_level;

View File

@ -309,6 +309,12 @@ void GSDevice::ClearCurrent()
m_mad = nullptr;
m_target_tmp = nullptr;
m_cas = nullptr;
m_temp_snapshot = nullptr;
}
void GSDevice::SetSnapshot()
{
m_temp_snapshot = m_current;
}
void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c)
@ -442,6 +448,25 @@ void GSDevice::ShadeBoost()
}
}
void GSDevice::Resize(int width, int height)
{
GSVector2i s = m_current->GetSize();
int multiplier = 1;
while (width > s.x || height > s.y)
{
s = m_current->GetSize() * GSVector2i(++multiplier);
}
if (ResizeTexture(&m_target_tmp, GSTexture::Type::RenderTarget, s.x, s.y))
{
const GSVector4 sRect(0, 0, 1, 1);
const GSVector4 dRect(0, 0, s.x, s.y);
StretchRect(m_current, sRect, m_target_tmp, dRect, ShaderConvert::COPY, false);
m_current = m_target_tmp;
}
}
bool GSDevice::ResizeTexture(GSTexture** t, GSTexture::Type type, int w, int h, bool clear, bool prefer_reuse)
{
if (t == NULL)

View File

@ -750,6 +750,8 @@ protected:
GSTexture* m_target_tmp = nullptr;
GSTexture* m_current = nullptr;
GSTexture* m_cas = nullptr;
GSTexture* m_temp_snapshot = nullptr; // No need to delete this, only ever points to m_current.
struct
{
size_t stride, start, count, limit;
@ -852,12 +854,16 @@ public:
__fi FeatureSupport Features() const { return m_features; }
__fi GSTexture* GetCurrent() const { return m_current; }
__fi GSTexture* GetSnapshot() const { return m_temp_snapshot; }
void ClearCurrent();
void SetSnapshot();
void Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c);
void Interlace(const GSVector2i& ds, int field, int mode, float yoffset);
void FXAA();
void ShadeBoost();
void Resize(int width, int height);
#ifndef PCSX2_CORE
void ExternalFX();
#endif

View File

@ -403,6 +403,14 @@ bool GSRenderer::Merge(int field)
if (GSConfig.FXAA)
g_gs_device->FXAA();
g_gs_device->SetSnapshot();
// Sharpens biinear at lower resolutions, almost nearest but with more uniform pixels.
if (GSConfig.LinearPresent == GSPostBilinearMode::BilinearSharp && (g_host_display->GetWindowWidth() > fs.x || g_host_display->GetWindowHeight() > fs.y))
{
g_gs_device->Resize(g_host_display->GetWindowWidth(), g_host_display->GetWindowHeight());
}
if (m_scanmask_used)
m_scanmask_used--;
@ -643,7 +651,7 @@ void GSRenderer::VSync(u32 field, bool registers_written)
const float shader_time = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - m_shader_time_start));
g_gs_device->PresentRect(current, src_uv, nullptr, draw_rect,
s_tv_shader_indices[GSConfig.TVShader], shader_time, GSConfig.LinearPresent);
s_tv_shader_indices[GSConfig.TVShader], shader_time, GSConfig.LinearPresent != GSPostBilinearMode::Off);
}
Host::EndPresentFrame();
@ -708,7 +716,7 @@ void GSRenderer::VSync(u32 field, bool registers_written)
Path::GetFileName(m_dump->GetPath())), Host::OSD_INFO_DURATION);
}
if (GSTexture* t = g_gs_device->GetCurrent())
if (GSTexture* t = g_gs_device->GetSnapshot())
{
const std::string path(m_snapshot + ".png");
if (t->Save(path))
@ -850,7 +858,7 @@ void GSRenderer::PresentCurrentFrame()
const float shader_time = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - m_shader_time_start));
g_gs_device->PresentRect(current, src_uv, nullptr, draw_rect,
s_tv_shader_indices[GSConfig.TVShader], shader_time, GSConfig.LinearPresent);
s_tv_shader_indices[GSConfig.TVShader], shader_time, GSConfig.LinearPresent != GSPostBilinearMode::Off);
}
Host::EndPresentFrame();

View File

@ -465,8 +465,12 @@ PostTab::PostTab(wxWindow* parent)
PaddedBoxSizer<wxStaticBoxSizer> shader_box(wxVERTICAL, this, "Custom Shader");
auto not_vk_prereq = [this] { return !m_is_vk_hw; };
PaddedBoxSizer<wxStaticBoxSizer> tex_filter_box(wxVERTICAL, this, "Debug");
auto* tex_filter_grid_box = new wxFlexGridSizer(2, space, space);
m_ui.addComboBoxAndLabel(tex_filter_grid_box, "Texture Filtering of Display:", "linear_present_mode", &theApp.m_gs_tex_display_list, IDC_LINEAR_PRESENT);
m_ui.addCheckBox(shader_box.inner, "Texture Filtering of Display", "linear_present", IDC_LINEAR_PRESENT);
m_ui.addCheckBox(shader_box.inner, "FXAA Shader (PgUp)", "fxaa", IDC_FXAA);
CheckboxPrereq shade_boost_check(m_ui.addCheckBox(shader_box.inner, "Enable Shade Boost", "ShadeBoost", IDC_SHADEBOOST));
@ -480,6 +484,7 @@ PostTab::PostTab(wxWindow* parent)
m_ui.addSliderAndLabel(shader_boost_grid, "Saturation:", "ShadeBoost_Saturation", 0, 100, 50, -1, shade_boost_check);
shade_boost_box->Add(shader_boost_grid, wxSizerFlags().Expand());
shader_box->Add(tex_filter_grid_box, wxSizerFlags().Expand());
shader_box->Add(shade_boost_box.outer, wxSizerFlags().Expand());
CheckboxPrereq ext_shader_check(m_ui.addCheckBox(shader_box.inner, "Enable External Shader", "shaderfx", IDC_SHADER_FX, not_vk_prereq));
@ -500,7 +505,6 @@ PostTab::PostTab(wxWindow* parent)
tv_box->AddGrowableCol(1);
m_ui.addComboBoxAndLabel(tv_box, "TV Shader:", "TVShader", &theApp.m_gs_tv_shaders);
shader_box->Add(tv_box, wxSizerFlags().Expand());
tab_box->Add(shader_box.outer, wxSizerFlags().Expand());
SetSizerAndFit(tab_box.outer);
}

View File

@ -303,7 +303,7 @@ Pcsx2Config::GSOptions::GSOptions()
PCRTCOffsets = false;
PCRTCOverscan = false;
IntegerScaling = false;
LinearPresent = true;
LinearPresent = GSPostBilinearMode::BilinearSmooth;
SyncToHostRefreshRate = false;
UseDebugDevice = false;
UseBlitSwapChain = false;
@ -381,6 +381,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
OpEqu(VsyncEnable) &&
OpEqu(InterlaceMode) &&
OpEqu(LinearPresent) &&
OpEqu(Zoom) &&
OpEqu(StretchY) &&
@ -477,7 +478,6 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(SyncToHostRefreshRate);
SettingsWrapEnumEx(AspectRatio, "AspectRatio", AspectRatioNames);
SettingsWrapEnumEx(FMVAspectRatioSwitch, "FMVAspectRatioSwitch", FMVAspectRatioSwitchNames);
SettingsWrapEntry(Zoom);
SettingsWrapEntry(StretchY);
SettingsWrapEntryEx(Crop[0], "CropLeft");
@ -532,7 +532,6 @@ void Pcsx2Config::GSOptions::ReloadIniSettings()
GSSettingBoolEx(PCRTCOffsets, "pcrtc_offsets");
GSSettingBoolEx(PCRTCOverscan, "pcrtc_overscan");
GSSettingBool(IntegerScaling);
GSSettingBoolEx(LinearPresent, "linear_present");
GSSettingBool(UseDebugDevice);
GSSettingBool(UseBlitSwapChain);
GSSettingBoolEx(DisableShaderCache, "disable_shader_cache");
@ -587,6 +586,7 @@ void Pcsx2Config::GSOptions::ReloadIniSettings()
GSSettingBool(LoadTextureReplacementsAsync);
GSSettingBool(PrecacheTextureReplacements);
GSSettingIntEnumEx(LinearPresent, "linear_present_mode");
GSSettingIntEnumEx(InterlaceMode, "deinterlace_mode");
GSSettingFloat(OsdScale);