From 2edf81cdb054c1db7a32e45c87514f8d4c11f5d9 Mon Sep 17 00:00:00 2001 From: Filoppi Date: Tue, 27 Jun 2023 03:23:08 +0300 Subject: Video: implement output resampling (upscaling/downscaling) methods --- Source/Core/Core/Config/GraphicsSettings.cpp | 2 + Source/Core/Core/Config/GraphicsSettings.h | 2 + .../Config/Graphics/EnhancementsWidget.cpp | 47 ++++++++++++++++++++++ .../DolphinQt/Config/Graphics/EnhancementsWidget.h | 1 + Source/Core/VideoCommon/PostProcessing.cpp | 41 +++++++++++++------ Source/Core/VideoCommon/VideoConfig.cpp | 1 + Source/Core/VideoCommon/VideoConfig.h | 12 ++++++ 7 files changed, 93 insertions(+), 13 deletions(-) (limited to 'Source/Core') diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp index 9a0dfbcd26..ad0059ca6d 100644 --- a/Source/Core/Core/Config/GraphicsSettings.cpp +++ b/Source/Core/Core/Config/GraphicsSettings.cpp @@ -118,6 +118,8 @@ const Info GFX_DRIVER_LIB_NAME{{System::GFX, "Settings", "DriverLib const Info GFX_ENHANCE_FORCE_TEXTURE_FILTERING{ {System::GFX, "Enhancements", "ForceTextureFiltering"}, TextureFilteringMode::Default}; const Info GFX_ENHANCE_MAX_ANISOTROPY{{System::GFX, "Enhancements", "MaxAnisotropy"}, 0}; +const Info GFX_ENHANCE_OUTPUT_RESAMPLING{ + {System::GFX, "Enhancements", "OutputResampling"}, OutputResamplingMode::Default}; const Info GFX_ENHANCE_POST_SHADER{ {System::GFX, "Enhancements", "PostProcessingShader"}, ""}; const Info GFX_ENHANCE_FORCE_TRUE_COLOR{{System::GFX, "Enhancements", "ForceTrueColor"}, diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h index 009b219136..165114e419 100644 --- a/Source/Core/Core/Config/GraphicsSettings.h +++ b/Source/Core/Core/Config/GraphicsSettings.h @@ -11,6 +11,7 @@ enum class AspectMode : int; enum class ShaderCompilationMode : int; enum class StereoMode : int; enum class TextureFilteringMode : int; +enum class OutputResamplingMode : int; enum class ColorCorrectionRegion : int; enum class TriState : int; @@ -101,6 +102,7 @@ extern const Info GFX_MODS_ENABLE; extern const Info GFX_ENHANCE_FORCE_TEXTURE_FILTERING; extern const Info GFX_ENHANCE_MAX_ANISOTROPY; // NOTE - this is x in (1 << x) +extern const Info GFX_ENHANCE_OUTPUT_RESAMPLING; extern const Info GFX_ENHANCE_POST_SHADER; extern const Info GFX_ENHANCE_FORCE_TRUE_COLOR; extern const Info GFX_ENHANCE_DISABLE_COPY_FILTER; diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp index 47e22ade53..67fd7da7b9 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp @@ -105,6 +105,22 @@ void EnhancementsWidget::CreateWidgets() m_texture_filtering_combo->addItem(tr("Force Linear and 16x Anisotropic"), TEXTURE_FILTERING_FORCE_LINEAR_ANISO_16X); + m_output_resampling_combo = new ToolTipComboBox(); + m_output_resampling_combo->addItem(tr("Default"), + static_cast(OutputResamplingMode::Default)); + m_output_resampling_combo->addItem(tr("Bilinear"), + static_cast(OutputResamplingMode::Bilinear)); + m_output_resampling_combo->addItem(tr("Bicubic"), + static_cast(OutputResamplingMode::Bicubic)); + m_output_resampling_combo->addItem(tr("Hermite"), + static_cast(OutputResamplingMode::Hermite)); + m_output_resampling_combo->addItem(tr("Catmull-Rom"), + static_cast(OutputResamplingMode::CatmullRom)); + m_output_resampling_combo->addItem(tr("Nearest Neighbor"), + static_cast(OutputResamplingMode::NearestNeighbor)); + m_output_resampling_combo->addItem(tr("Sharp Bilinear"), + static_cast(OutputResamplingMode::SharpBilinear)); + m_configure_color_correction = new ToolTipPushButton(tr("Configure")); m_pp_effect = new ToolTipComboBox(); @@ -136,6 +152,10 @@ void EnhancementsWidget::CreateWidgets() enhancements_layout->addWidget(m_texture_filtering_combo, row, 1, 1, -1); ++row; + enhancements_layout->addWidget(new QLabel(tr("Output Resampling:")), row, 0); + enhancements_layout->addWidget(m_output_resampling_combo, row, 1, 1, -1); + ++row; + enhancements_layout->addWidget(new QLabel(tr("Color Correction:")), row, 0); enhancements_layout->addWidget(m_configure_color_correction, row, 1, 1, -1); ++row; @@ -195,6 +215,8 @@ void EnhancementsWidget::ConnectWidgets() [this](int) { SaveSettings(); }); connect(m_texture_filtering_combo, qOverload(&QComboBox::currentIndexChanged), [this](int) { SaveSettings(); }); + connect(m_output_resampling_combo, qOverload(&QComboBox::currentIndexChanged), + [this](int) { SaveSettings(); }); connect(m_pp_effect, qOverload(&QComboBox::currentIndexChanged), [this](int) { SaveSettings(); }); connect(m_3d_mode, qOverload(&QComboBox::currentIndexChanged), [this] { @@ -325,6 +347,14 @@ void EnhancementsWidget::LoadSettings() break; } + // Resampling + const OutputResamplingMode output_resampling_mode = + Config::Get(Config::GFX_ENHANCE_OUTPUT_RESAMPLING); + m_output_resampling_combo->setCurrentIndex(static_cast(output_resampling_mode)); + + m_output_resampling_combo->setEnabled(g_Config.backend_info.bSupportsPostProcessing); + + // Color Correction m_configure_color_correction->setEnabled(g_Config.backend_info.bSupportsPostProcessing); // Post Processing Shader @@ -413,6 +443,10 @@ void EnhancementsWidget::SaveSettings() break; } + const int output_resampling_selection = m_output_resampling_combo->currentData().toInt(); + Config::SetBaseOrCurrent(Config::GFX_ENHANCE_OUTPUT_RESAMPLING, + static_cast(output_resampling_selection)); + const bool anaglyph = g_Config.stereo_mode == StereoMode::Anaglyph; const bool passive = g_Config.stereo_mode == StereoMode::Passive; Config::SetBaseOrCurrent(Config::GFX_ENHANCE_POST_SHADER, @@ -455,6 +489,16 @@ void EnhancementsWidget::AddDescriptions() "scaling filter selected by the game.

Any option except 'Default' will alter the look " "of the game's textures and might cause issues in a small number of " "games.

If unsure, select 'Default'."); + static const char TR_OUTPUT_RESAMPLING_DESCRIPTION[] = QT_TR_NOOP( + "Affects how the game output image is upscaled or downscaled to the window resolution.
" + "\"Default\" will rely on the GPU internal bilinear sampler which isn't gamma corrected." + "
\"Bilinear\" (gamma corrected) is a good compromise between quality and performance." + "
\"Bicubic\" is smoother than \"Bilinear\"." + "
\"Hermite\" might offer the best quality when upscaling," + " at a slightly bigger perform cost.
\"Catmull-Rom\" is best for downscaling." + "
\"Nearest Neighbor\" doesn't do any resampling, select if you like a pixelated look." + "
\"Sharp Bilinear\" works best with 2D games at low resolutions, use if you like a" + " sharp look.

If unsure, select 'Default'."); static const char TR_COLOR_CORRECTION_DESCRIPTION[] = QT_TR_NOOP("A group of features to make the colors more accurate, matching the color space " "Wii and GC games were meant for."); @@ -537,6 +581,9 @@ void EnhancementsWidget::AddDescriptions() m_texture_filtering_combo->SetTitle(tr("Texture Filtering")); m_texture_filtering_combo->SetDescription(tr(TR_FORCE_TEXTURE_FILTERING_DESCRIPTION)); + m_output_resampling_combo->SetTitle(tr("Output Resampling")); + m_output_resampling_combo->SetDescription(tr(TR_OUTPUT_RESAMPLING_DESCRIPTION)); + m_configure_color_correction->SetTitle(tr("Color Correction")); m_configure_color_correction->SetDescription(tr(TR_COLOR_CORRECTION_DESCRIPTION)); diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h index 4d2cdcd5b5..34879d17b7 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h @@ -39,6 +39,7 @@ private: ConfigChoice* m_ir_combo; ToolTipComboBox* m_aa_combo; ToolTipComboBox* m_texture_filtering_combo; + ToolTipComboBox* m_output_resampling_combo; ToolTipComboBox* m_pp_effect; ToolTipPushButton* m_configure_color_correction; QPushButton* m_configure_pp_effect; diff --git a/Source/Core/VideoCommon/PostProcessing.cpp b/Source/Core/VideoCommon/PostProcessing.cpp index c3a245629f..1de4c311c2 100644 --- a/Source/Core/VideoCommon/PostProcessing.cpp +++ b/Source/Core/VideoCommon/PostProcessing.cpp @@ -486,23 +486,29 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, MathUtil::Rectangle src_rect = src; g_gfx->SetSamplerState(0, RenderState::GetLinearSamplerState()); + g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState()); g_gfx->SetTexture(0, src_tex); + g_gfx->SetTexture(1, src_tex); - const bool is_color_correction_active = IsColorCorrectionActive(); + const bool needs_color_correction = IsColorCorrectionActive(); + // Rely on the default (bi)linear sampler with the default mode + // (it might not be gamma corrected). + const bool needs_resampling = + g_ActiveConfig.output_resampling_mode > OutputResamplingMode::Default; const bool needs_intermediary_buffer = NeedsIntermediaryBuffer(); + const bool needs_default_pipeline = needs_color_correction || needs_resampling; const AbstractPipeline* final_pipeline = m_pipeline.get(); std::vector* uniform_staging_buffer = &m_default_uniform_staging_buffer; bool default_uniform_staging_buffer = true; + const MathUtil::Rectangle present_rect = g_presenter->GetTargetRectangle(); // Intermediary pass. - // We draw to a high quality intermediary texture for two reasons: + // We draw to a high quality intermediary texture for a couple reasons: + // -Consistently do high quality gamma corrected resampling (upscaling/downscaling) // -Keep quality for gamma and gamut conversions, and HDR output // (low bit depths lose too much quality with gamma conversions) - // -We make a texture of the exact same res as the source one, - // because all the post process shaders we already had assume that - // the source texture size (EFB) is different from the swap chain - // texture size (which matches the window size). - if (m_default_pipeline && is_color_correction_active && needs_intermediary_buffer) + // -Keep the post process phase in linear space, to better operate with colors + if (m_default_pipeline && needs_default_pipeline && needs_intermediary_buffer) { AbstractFramebuffer* const previous_framebuffer = g_gfx->GetCurrentFramebuffer(); @@ -512,13 +518,18 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, // so it would be a waste to allocate two layers (see "bUsesExplictQuadBuffering"). const u32 target_layers = copy_all_layers ? src_tex->GetLayers() : 1; + const u32 target_width = + needs_resampling ? present_rect.GetWidth() : static_cast(src_rect.GetWidth()); + const u32 target_height = + needs_resampling ? present_rect.GetHeight() : static_cast(src_rect.GetHeight()); + if (!m_intermediary_frame_buffer || !m_intermediary_color_texture || - m_intermediary_color_texture.get()->GetWidth() != static_cast(src_rect.GetWidth()) || - m_intermediary_color_texture.get()->GetHeight() != static_cast(src_rect.GetHeight()) || + m_intermediary_color_texture.get()->GetWidth() != target_width || + m_intermediary_color_texture.get()->GetHeight() != target_height || m_intermediary_color_texture.get()->GetLayers() != target_layers) { const TextureConfig intermediary_color_texture_config( - src_rect.GetWidth(), src_rect.GetHeight(), 1, target_layers, src_tex->GetSamples(), + target_width, target_height, 1, target_layers, src_tex->GetSamples(), s_intermediary_buffer_format, AbstractTextureFlag_RenderTarget); m_intermediary_color_texture = g_gfx->CreateTexture(intermediary_color_texture_config, "Intermediary post process texture"); @@ -530,7 +541,7 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, g_gfx->SetFramebuffer(m_intermediary_frame_buffer.get()); FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(), - g_presenter->GetTargetRectangle(), uniform_staging_buffer->data(), + present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer); g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(), static_cast(uniform_staging_buffer->size())); @@ -544,6 +555,7 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, src_rect = m_intermediary_color_texture->GetRect(); src_tex = m_intermediary_color_texture.get(); g_gfx->SetTexture(0, src_tex); + g_gfx->SetTexture(1, src_tex); // The "m_intermediary_color_texture" has already copied // from the specified source layer onto its first one. // If we query for a layer that the source texture doesn't have, @@ -557,7 +569,7 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, // If we have no custom user shader selected, and color correction // is active, directly run the fixed pipeline shader instead of // doing two passes, with the second one doing nothing useful. - if (m_default_pipeline && is_color_correction_active) + if (m_default_pipeline && needs_default_pipeline) { final_pipeline = m_default_pipeline.get(); } @@ -580,7 +592,7 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, if (final_pipeline) { FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(), - g_presenter->GetTargetRectangle(), uniform_staging_buffer->data(), + present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer); g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(), static_cast(uniform_staging_buffer->size())); @@ -610,6 +622,7 @@ std::string PostProcessing::GetUniformBufferHeader(bool user_post_process) const ss << " int src_layer;\n"; ss << " uint time;\n"; + ss << " int resampling_method;\n"; ss << " int correct_color_space;\n"; ss << " int game_color_space;\n"; ss << " int correct_gamma;\n"; @@ -816,6 +829,7 @@ struct BuiltinUniforms std::array src_rect; s32 src_layer; u32 time; + s32 resampling_method; s32 correct_color_space; s32 game_color_space; s32 correct_gamma; @@ -861,6 +875,7 @@ void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle& src, builtin_uniforms.src_layer = static_cast(src_layer); builtin_uniforms.time = static_cast(m_timer.ElapsedMs()); + builtin_uniforms.resampling_method = static_cast(g_ActiveConfig.output_resampling_mode); // Color correction related uniforms. // These are mainly used by the "m_default_pixel_shader", // but should also be accessible to all other shaders. diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 42bf178047..83dc5eb53e 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -133,6 +133,7 @@ void VideoConfig::Refresh() texture_filtering_mode = Config::Get(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING); iMaxAnisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY); + output_resampling_mode = Config::Get(Config::GFX_ENHANCE_OUTPUT_RESAMPLING); sPostProcessingShader = Config::Get(Config::GFX_ENHANCE_POST_SHADER); bForceTrueColor = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR); bDisableCopyFilter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 20f4aa8a28..affbf78dec 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -52,6 +52,17 @@ enum class TextureFilteringMode : int Linear, }; +enum class OutputResamplingMode : int +{ + Default, + Bilinear, + Bicubic, + Hermite, + CatmullRom, + NearestNeighbor, + SharpBilinear, +}; + enum class ColorCorrectionRegion : int { SMPTE_NTSCM, @@ -103,6 +114,7 @@ struct VideoConfig final bool bSSAA = false; int iEFBScale = 0; TextureFilteringMode texture_filtering_mode = TextureFilteringMode::Default; + OutputResamplingMode output_resampling_mode = OutputResamplingMode::Default; int iMaxAnisotropy = 0; std::string sPostProcessingShader; bool bForceTrueColor = false; -- cgit v1.2.3 From ca93a5191fef40947a6fac935ce814fca8a2a295 Mon Sep 17 00:00:00 2001 From: Sam Belliveau Date: Wed, 28 Jun 2023 16:14:26 -0400 Subject: Video: Added Box Resampling Edited by Filoppi --- Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp | 8 ++++++-- Source/Core/VideoCommon/VideoConfig.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Source/Core') diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp index 67fd7da7b9..ee525ef001 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp @@ -120,6 +120,8 @@ void EnhancementsWidget::CreateWidgets() static_cast(OutputResamplingMode::NearestNeighbor)); m_output_resampling_combo->addItem(tr("Sharp Bilinear"), static_cast(OutputResamplingMode::SharpBilinear)); + m_output_resampling_combo->addItem(tr("Box Resampling"), + static_cast(OutputResamplingMode::BoxResampling)); m_configure_color_correction = new ToolTipPushButton(tr("Configure")); @@ -497,8 +499,10 @@ void EnhancementsWidget::AddDescriptions() "
\"Hermite\" might offer the best quality when upscaling," " at a slightly bigger perform cost.
\"Catmull-Rom\" is best for downscaling." "
\"Nearest Neighbor\" doesn't do any resampling, select if you like a pixelated look." - "
\"Sharp Bilinear\" works best with 2D games at low resolutions, use if you like a" - " sharp look.

If unsure, select 'Default'."); + "
\"Sharp Bilinear\" works best with 2D games at low resolutions, use if you like a sharp" + " look." + "
\"Box Resampling\" is most expensive but also most accurate downscaling method." + "
If unsure, select 'Default'."); static const char TR_COLOR_CORRECTION_DESCRIPTION[] = QT_TR_NOOP("A group of features to make the colors more accurate, matching the color space " "Wii and GC games were meant for."); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index affbf78dec..dcdc631a40 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -61,6 +61,7 @@ enum class OutputResamplingMode : int CatmullRom, NearestNeighbor, SharpBilinear, + BoxResampling, }; enum class ColorCorrectionRegion : int -- cgit v1.2.3 From 39d96a21a8428a6372784ea2c23a687e120e22ad Mon Sep 17 00:00:00 2001 From: Sam Belliveau Date: Thu, 3 Aug 2023 18:53:21 -0400 Subject: Video: Improved Tooltips & Bicubic (#5) Edited by Filoppi --- .../Config/Graphics/EnhancementsWidget.cpp | 59 ++++++++++++++-------- Source/Core/VideoCommon/VideoConfig.h | 7 ++- 2 files changed, 41 insertions(+), 25 deletions(-) (limited to 'Source/Core') diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp index ee525ef001..f181780749 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp @@ -110,18 +110,16 @@ void EnhancementsWidget::CreateWidgets() static_cast(OutputResamplingMode::Default)); m_output_resampling_combo->addItem(tr("Bilinear"), static_cast(OutputResamplingMode::Bilinear)); - m_output_resampling_combo->addItem(tr("Bicubic"), - static_cast(OutputResamplingMode::Bicubic)); - m_output_resampling_combo->addItem(tr("Hermite"), - static_cast(OutputResamplingMode::Hermite)); - m_output_resampling_combo->addItem(tr("Catmull-Rom"), + m_output_resampling_combo->addItem(tr("Bicubic: B-Spline"), + static_cast(OutputResamplingMode::BSpline)); + m_output_resampling_combo->addItem(tr("Bicubic: Mitchell-Netravali"), + static_cast(OutputResamplingMode::MitchellNetravali)); + m_output_resampling_combo->addItem(tr("Bicubic: Catmull-Rom"), static_cast(OutputResamplingMode::CatmullRom)); - m_output_resampling_combo->addItem(tr("Nearest Neighbor"), - static_cast(OutputResamplingMode::NearestNeighbor)); m_output_resampling_combo->addItem(tr("Sharp Bilinear"), static_cast(OutputResamplingMode::SharpBilinear)); - m_output_resampling_combo->addItem(tr("Box Resampling"), - static_cast(OutputResamplingMode::BoxResampling)); + m_output_resampling_combo->addItem(tr("Area Sampling"), + static_cast(OutputResamplingMode::AreaSampling)); m_configure_color_correction = new ToolTipPushButton(tr("Configure")); @@ -491,18 +489,37 @@ void EnhancementsWidget::AddDescriptions() "scaling filter selected by the game.

Any option except 'Default' will alter the look " "of the game's textures and might cause issues in a small number of " "games.

If unsure, select 'Default'."); - static const char TR_OUTPUT_RESAMPLING_DESCRIPTION[] = QT_TR_NOOP( - "Affects how the game output image is upscaled or downscaled to the window resolution.
" - "\"Default\" will rely on the GPU internal bilinear sampler which isn't gamma corrected." - "
\"Bilinear\" (gamma corrected) is a good compromise between quality and performance." - "
\"Bicubic\" is smoother than \"Bilinear\"." - "
\"Hermite\" might offer the best quality when upscaling," - " at a slightly bigger perform cost.
\"Catmull-Rom\" is best for downscaling." - "
\"Nearest Neighbor\" doesn't do any resampling, select if you like a pixelated look." - "
\"Sharp Bilinear\" works best with 2D games at low resolutions, use if you like a sharp" - " look." - "
\"Box Resampling\" is most expensive but also most accurate downscaling method." - "
If unsure, select 'Default'."); + static const char TR_OUTPUT_RESAMPLING_DESCRIPTION[] = + QT_TR_NOOP("Affects how the game output is scaled to the window resolution." + "
The performance mostly depends on the number of samples each method uses." + "
Compared to SSAA, resampling is useful in case the output window" + "
resolution isn't a multiplier of the native emulation resolution." + + "

Default - [fastest]" + "
Internal GPU bilinear sampler which is not gamma corrected." + "
This setting might be ignored if gamma correction is forced on." + + "

Bilinear - [4 samples]" + "
Gamma corrected linear interpolation between pixels." + + "

Bicubic - [16 samples]" + "
Gamma corrected cubic interpolation between pixels." + "
Good when rescaling between close resolutions. i.e 1080p and 1440p." + "
Comes in various flavors:" + "
B-Spline: Blurry, but avoids all lobing artifacts" + "
Mitchell-Netravali: Good middle ground between blurry and lobing" + "
Catmull-Rom: Sharper, but can cause lobing artifacts" + + "

Sharp Bilinear - [1-4 samples]" + "
Similarly to \"Nearest Neighbor\", it maintains a sharp look," + "
but also does some blending to avoid shimmering." + "
Works best with 2D games at low resolutions." + + "

Area Sampling - [up to 324 samples]" + "
Weights pixels by the percentage of area they occupy. Gamma corrected." + "
Best for down scaling by more than 2x." + + "

If unsure, select 'Default'."); static const char TR_COLOR_CORRECTION_DESCRIPTION[] = QT_TR_NOOP("A group of features to make the colors more accurate, matching the color space " "Wii and GC games were meant for."); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index dcdc631a40..6e34a43934 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -56,12 +56,11 @@ enum class OutputResamplingMode : int { Default, Bilinear, - Bicubic, - Hermite, + BSpline, + MitchellNetravali, CatmullRom, - NearestNeighbor, SharpBilinear, - BoxResampling, + AreaSampling, }; enum class ColorCorrectionRegion : int -- cgit v1.2.3 From 80b453082dff9545e7b040fbe546055dac310b5c Mon Sep 17 00:00:00 2001 From: Filoppi Date: Sun, 6 Aug 2023 03:11:19 +0300 Subject: Video: fix post process shaders with parameters failing to build on OpenGL This was because the shader uniforms between the pixel and vertex shaders were willingly left different, to avoid filling the vertex shader with unnecessary params. Turns out all backends are fine with this except OGL. The new behaviour is now much more consistent and well explained, the "default" shaders are the ones that always run, and the non default ones are the user selected ones (if any). --- Source/Core/VideoCommon/PostProcessing.cpp | 66 +++++++++++++++++++----------- Source/Core/VideoCommon/PostProcessing.h | 3 +- 2 files changed, 44 insertions(+), 25 deletions(-) (limited to 'Source/Core') diff --git a/Source/Core/VideoCommon/PostProcessing.cpp b/Source/Core/VideoCommon/PostProcessing.cpp index 1de4c311c2..49b05e6762 100644 --- a/Source/Core/VideoCommon/PostProcessing.cpp +++ b/Source/Core/VideoCommon/PostProcessing.cpp @@ -419,9 +419,9 @@ std::vector PostProcessing::GetPassiveShaderList() bool PostProcessing::Initialize(AbstractTextureFormat format) { m_framebuffer_format = format; - // CompilePixelShader must be run first if configuration options are used. + // CompilePixelShader() must be run first if configuration options are used. // Otherwise the UBO has a different member list between vertex and pixel - // shaders, which is a link error. + // shaders, which is a link error on some backends. if (!CompilePixelShader() || !CompileVertexShader() || !CompilePipeline()) return false; @@ -541,8 +541,8 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, g_gfx->SetFramebuffer(m_intermediary_frame_buffer.get()); FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(), - present_rect, uniform_staging_buffer->data(), - !default_uniform_staging_buffer); + present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer, + true); g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(), static_cast(uniform_staging_buffer->size())); @@ -592,8 +592,8 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, if (final_pipeline) { FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(), - present_rect, uniform_staging_buffer->data(), - !default_uniform_staging_buffer); + present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer, + false); g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(), static_cast(uniform_staging_buffer->size())); @@ -621,6 +621,9 @@ std::string PostProcessing::GetUniformBufferHeader(bool user_post_process) const // The first (but not necessarily only) source layer we target ss << " int src_layer;\n"; ss << " uint time;\n"; + ss << " int graphics_api;\n"; + // If true, it's an intermediary buffer (including the first), if false, it's the final one + ss << " int intermediary_buffer;\n"; ss << " int resampling_method;\n"; ss << " int correct_color_space;\n"; @@ -755,6 +758,7 @@ void SetOutput(float4 color) #define GetOption(x) (x) #define OptionEnabled(x) ((x) != 0) +#define OptionDisabled(x) ((x) == 0) )"; return ss.str(); @@ -765,13 +769,9 @@ std::string PostProcessing::GetFooter() const return {}; } -bool PostProcessing::CompileVertexShader() +std::string GetVertexShaderBody() { std::ostringstream ss; - // We never need the user selected post process custom uniforms in the vertex shader - const bool user_post_process = false; - ss << GetUniformBufferHeader(user_post_process); - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) { ss << "VARYING_LOCATION(0) out VertexData {\n"; @@ -792,21 +792,34 @@ bool PostProcessing::CompileVertexShader() // Vulkan Y needs to be inverted on every pass if (g_ActiveConfig.backend_info.api_type == APIType::Vulkan) + { ss << " opos.y = -opos.y;\n"; - - std::string s2 = ss.str(); - s2 += "}\n"; - m_default_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, s2, - "Default post-processing vertex shader"); - - // OpenGL Y needs to be inverted once only (in the last pass) - if (g_ActiveConfig.backend_info.api_type == APIType::OpenGL) - ss << " opos.y = -opos.y;\n"; + } + // OpenGL Y needs to be inverted in all passes except the last one + else if (g_ActiveConfig.backend_info.api_type == APIType::OpenGL) + { + ss << " if (intermediary_buffer != 0)\n"; + ss << " opos.y = -opos.y;\n"; + } ss << "}\n"; + return ss.str(); +} + +bool PostProcessing::CompileVertexShader() +{ + std::ostringstream ss_default; + ss_default << GetUniformBufferHeader(false); + ss_default << GetVertexShaderBody(); + m_default_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss_default.str(), + "Default post-processing vertex shader"); + std::ostringstream ss; + ss << GetUniformBufferHeader(true); + ss << GetVertexShaderBody(); m_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss.str(), "Post-processing vertex shader"); + if (!m_default_vertex_shader || !m_vertex_shader) { PanicAlertFmt("Failed to compile post-processing vertex shader"); @@ -829,6 +842,8 @@ struct BuiltinUniforms std::array src_rect; s32 src_layer; u32 time; + s32 graphics_api; + s32 intermediary_buffer; s32 resampling_method; s32 correct_color_space; s32 game_color_space; @@ -853,7 +868,7 @@ void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle& src, const AbstractTexture* src_tex, int src_layer, const MathUtil::Rectangle& dst, const MathUtil::Rectangle& wnd, u8* buffer, - bool user_post_process) + bool user_post_process, bool intermediary_buffer) { const float rcp_src_width = 1.0f / src_tex->GetWidth(); const float rcp_src_height = 1.0f / src_tex->GetHeight(); @@ -874,6 +889,8 @@ void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle& src, static_cast(src.GetHeight()) * rcp_src_height}; builtin_uniforms.src_layer = static_cast(src_layer); builtin_uniforms.time = static_cast(m_timer.ElapsedMs()); + builtin_uniforms.graphics_api = static_cast(g_ActiveConfig.backend_info.api_type); + builtin_uniforms.intermediary_buffer = static_cast(intermediary_buffer); builtin_uniforms.resampling_method = static_cast(g_ActiveConfig.output_resampling_mode); // Color correction related uniforms. @@ -898,6 +915,8 @@ void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle& src, std::memcpy(buffer, &builtin_uniforms, sizeof(builtin_uniforms)); buffer += sizeof(builtin_uniforms); + // Don't include the custom pp shader options if they are not necessary, + // having mismatching uniforms between different shaders can cause issues on some backends if (!user_post_process) return; @@ -1015,8 +1034,7 @@ bool PostProcessing::CompilePipeline() const bool needs_intermediary_buffer = NeedsIntermediaryBuffer(); AbstractPipelineConfig config = {}; - config.vertex_shader = - needs_intermediary_buffer ? m_vertex_shader.get() : m_default_vertex_shader.get(); + config.vertex_shader = m_default_vertex_shader.get(); // This geometry shader will take care of reading both layer 0 and 1 on the source texture, // and writing to both layer 0 and 1 on the render target. config.geometry_shader = UseGeometryShaderForPostProcess(needs_intermediary_buffer) ? @@ -1033,7 +1051,7 @@ bool PostProcessing::CompilePipeline() if (config.pixel_shader) m_default_pipeline = g_gfx->CreatePipeline(config); - config.vertex_shader = m_default_vertex_shader.get(); + config.vertex_shader = m_vertex_shader.get(); config.geometry_shader = UseGeometryShaderForPostProcess(false) ? g_shader_cache->GetTexcoordGeometryShader() : nullptr; diff --git a/Source/Core/VideoCommon/PostProcessing.h b/Source/Core/VideoCommon/PostProcessing.h index b8b648d2d0..b636f3b133 100644 --- a/Source/Core/VideoCommon/PostProcessing.h +++ b/Source/Core/VideoCommon/PostProcessing.h @@ -124,7 +124,8 @@ protected: size_t CalculateUniformsSize(bool user_post_process) const; void FillUniformBuffer(const MathUtil::Rectangle& src, const AbstractTexture* src_tex, int src_layer, const MathUtil::Rectangle& dst, - const MathUtil::Rectangle& wnd, u8* buffer, bool user_post_process); + const MathUtil::Rectangle& wnd, u8* buffer, bool user_post_process, + bool intermediary_buffer); // Timer for determining our time value Common::Timer m_timer; -- cgit v1.2.3