diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 9bcb046b3..e00d54ea5 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -163,8 +163,12 @@ @string/scaling_filter_bicubic @string/scaling_filter_gaussian @string/scaling_filter_scale_force + @string/scaling_filter_scale_fx + @string/scaling_filter_lanczos @string/scaling_filter_fsr @string/scaling_filter_fsr2 + @string/scaling_filter_crt_easymode + @string/scaling_filter_crt_royale @@ -175,6 +179,10 @@ 4 5 6 + 7 + 8 + 9 + 10 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 461436a3d..58dfbc2a1 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -654,8 +654,12 @@ Bicubic Gaussian ScaleForce + ScaleFX + Lanczos AMD FidelityFX™ Super Resolution AMD FidelityFX™ Super Resolution 2.0 + CRT EasyMode + CRT Royale None diff --git a/src/citron/configuration/shared_translation.cpp b/src/citron/configuration/shared_translation.cpp index 9d8e48701..46fa6cfcf 100644 --- a/src/citron/configuration/shared_translation.cpp +++ b/src/citron/configuration/shared_translation.cpp @@ -1,5 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "citron/configuration/shared_translation.h" @@ -130,6 +130,20 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { INSERT(Settings, lanczos_quality, tr("Lanczos Quality:"), tr("The quality of the Lanczos filter. Higher is sharper but more expensive.")); INSERT(Settings, fsr2_quality_mode, tr("FSR 2.0 Quality Mode:"), tr("Selects the quality mode for FSR 2.0 upscaling. Quality provides better image quality, Performance provides better performance.")); + INSERT(Settings, crt_scanline_strength, tr("CRT Scanline Strength:"), + tr("Controls the intensity of scanlines. Higher values create more pronounced horizontal lines.")); + INSERT(Settings, crt_curvature, tr("CRT Curvature:"), + tr("Applies barrel distortion to simulate the curved screen of a CRT monitor.")); + INSERT(Settings, crt_gamma, tr("CRT Gamma:"), + tr("Adjusts the gamma correction curve. Higher values brighten the image, lower values darken it.")); + INSERT(Settings, crt_bloom, tr("CRT Bloom:"), + tr("Controls the glow effect around bright areas, simulating phosphor persistence.")); + INSERT(Settings, crt_mask_type, tr("CRT Mask Type:"), + tr("Selects the phosphor mask pattern: None, Aperture Grille (vertical stripes), or Shadow Mask (triangular pattern).")); + INSERT(Settings, crt_brightness, tr("CRT Brightness:"), + tr("Adjusts overall brightness of the CRT effect. Use to compensate for darkening from other effects.")); + INSERT(Settings, crt_alpha, tr("CRT Alpha:"), + tr("Controls transparency of the CRT effect. Lower values make the effect more transparent.")); INSERT(Settings, frame_skipping, tr("Frame Skipping:"), tr("Skips frames to maintain performance when the system cannot keep up with the target frame rate.")); @@ -426,6 +440,8 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { PAIR(ScalingFilter, ScaleFx, tr("ScaleFX")), PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")), PAIR(ScalingFilter, Fsr2, tr("AMD FidelityFX™️ Super Resolution 2.0")), + PAIR(ScalingFilter, CRTEasyMode, tr("CRT EasyMode")), + PAIR(ScalingFilter, CRTRoyale, tr("CRT Royale")), }}); translations->insert({Settings::EnumMetadata::Index(), { diff --git a/src/citron/configuration/shared_translation.h b/src/citron/configuration/shared_translation.h index fad796d8d..71ec60f88 100644 --- a/src/citron/configuration/shared_translation.h +++ b/src/citron/configuration/shared_translation.h @@ -1,5 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -46,6 +46,10 @@ static const std::map scaling_filter_texts_map QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleFX"))}, {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, {Settings::ScalingFilter::Fsr2, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR 2.0"))}, + {Settings::ScalingFilter::CRTEasyMode, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "CRT EasyMode"))}, + {Settings::ScalingFilter::CRTRoyale, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "CRT Royale"))}, }; static const std::map use_docked_mode_texts_map = { diff --git a/src/common/settings.h b/src/common/settings.h index e6c0f5500..7dd29b402 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -1,5 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -350,6 +350,71 @@ struct Values { true, true}; + // CRT Shader Settings (only active when CRT filter is selected) + SwitchableSetting crt_scanline_strength{linkage, + 1.0f, // 100/100 = 1.0 (range 0-200, actual 0.0-2.0) + 0.0f, + 2.0f, + "crt_scanline_strength", + Category::Renderer, + Specialization::Scalar, + true, + true}; + SwitchableSetting crt_curvature{linkage, + 0.0f, + 0.0f, + 1.0f, + "crt_curvature", + Category::Renderer, + Specialization::Scalar, + true, + true}; + SwitchableSetting crt_gamma{linkage, + 1.0f, // 100 maps to 1.0 (range 1-300, actual 1.0-3.0) + 1.0f, + 3.0f, + "crt_gamma", + Category::Renderer, + Specialization::Scalar, + true, + true}; + SwitchableSetting crt_bloom{linkage, + 0.33f, // 33/100 = 0.33 (range 0-100, actual 0.0-1.0) + 0.0f, + 1.0f, + "crt_bloom", + Category::Renderer, + Specialization::Scalar, + true, + true}; + SwitchableSetting crt_mask_type{linkage, + 1, // Already correct + 0, + 2, + "crt_mask_type", + Category::Renderer, + Specialization::Scalar, + true, + true}; // 0=none, 1=aperture, 2=shadow + SwitchableSetting crt_brightness{linkage, + 1.0f, // Default brightness (1.0 = no change) + 0.0f, + 2.0f, + "crt_brightness", + Category::Renderer, + Specialization::Scalar, + true, + true}; + SwitchableSetting crt_alpha{linkage, + 1.0f, // Default alpha (1.0 = fully opaque) + 0.0f, + 1.0f, + "crt_alpha", + Category::Renderer, + Specialization::Scalar, + true, + true}; + SwitchableSetting lanczos_quality{linkage, 3, // Default value diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index 2fcf4b79b..1b654bfb0 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -1,5 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -673,7 +673,9 @@ enum class ScalingFilter : u32 { Lanczos = 6, Fsr = 7, Fsr2 = 8, - MaxEnum = 9, + CRTEasyMode = 9, + CRTRoyale = 10, + MaxEnum = 11, }; template <> @@ -689,6 +691,8 @@ EnumMetadata::Canonicalizations() { {"Lanczos", ScalingFilter::Lanczos}, {"Fsr", ScalingFilter::Fsr}, {"Fsr2", ScalingFilter::Fsr2}, + {"CRTEasyMode", ScalingFilter::CRTEasyMode}, + {"CRTRoyale", ScalingFilter::CRTRoyale}, {"MaxEnum", ScalingFilter::MaxEnum}, }; } @@ -876,6 +880,7 @@ inline u32 EnumMetadata::Index() { return 26; } + template inline std::string CanonicalizeEnum(Type id) { const auto group = EnumMetadata::Canonicalizations(); diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index a14010350..a24cc5ecc 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: 2018 yuzu Emulator Project -# SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +# SPDX-FileCopyrightText: 2026 citron Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later set(FIDELITYFX_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/externals/FidelityFX-FSR/ffx-fsr) @@ -74,6 +74,7 @@ set(SHADER_FILES vulkan_present_scaleforce_fp32.frag vulkan_present_scalefx_fp16.frag vulkan_present_scalefx_fp32.frag + vulkan_crt_easymode.frag vulkan_quad_indexed.comp vulkan_taa.frag vulkan_taa.vert diff --git a/src/video_core/host_shaders/vulkan_crt_easymode.frag b/src/video_core/host_shaders/vulkan_crt_easymode.frag new file mode 100644 index 000000000..bae9dd3aa --- /dev/null +++ b/src/video_core/host_shaders/vulkan_crt_easymode.frag @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later +// +// CRT EasyMode shader - Single-pass CRT effects +// Based on Libretro's crt-easymode shader +// https://github.com/libretro/common-shaders/blob/master/crt/shaders/crt-easymode.cg + +#version 460 core + +layout(location = 0) in vec2 frag_tex_coord; +layout(location = 0) out vec4 color; + +layout(binding = 0) uniform sampler2D color_texture; + +layout(push_constant) uniform CRTPushConstants { + layout(offset = 132) float scanline_strength; + layout(offset = 136) float curvature; + layout(offset = 140) float gamma; + layout(offset = 144) float bloom; + layout(offset = 148) int mask_type; + layout(offset = 152) float brightness; + layout(offset = 156) float alpha; + layout(offset = 160) float screen_width; + layout(offset = 164) float screen_height; +} crt_params; + +const float PI = 3.141592653589793; + +// Apply barrel distortion (curvature) +vec2 applyCurvature(vec2 coord) { + if (crt_params.curvature <= 0.0) { + return coord; + } + + vec2 centered = coord - 0.5; + float dist = length(centered); + float distortion = 1.0 + crt_params.curvature * dist * dist; + vec2 curved = centered * distortion + 0.5; + + // Clamp to valid texture coordinates + return clamp(curved, vec2(0.0), vec2(1.0)); +} + +// Generate scanlines +float scanline(float y) { + if (crt_params.scanline_strength <= 0.0) { + return 1.0; + } + + float scanline_pos = y * crt_params.screen_height; + float scanline_factor = abs(sin(scanline_pos * PI)); + + // Make scanlines more subtle + return 1.0 - crt_params.scanline_strength * scanline_factor * 0.5; +} + +// Apply phosphor mask (aperture grille or shadow mask) +vec3 applyMask(vec2 coord) { + if (crt_params.mask_type == 0) { + return vec3(1.0); // No mask + } + + vec2 screen_pos = coord * vec2(crt_params.screen_width, crt_params.screen_height); + + if (crt_params.mask_type == 1) { + // Aperture grille (vertical RGB stripes) + float mask = sin(screen_pos.x * PI * 3.0) * 0.5 + 0.5; + return vec3( + 1.0 - mask * 0.2, + 1.0 - mask * 0.15, + 1.0 - mask * 0.2 + ); + } else if (crt_params.mask_type == 2) { + // Shadow mask (triangular pattern) + float x = screen_pos.x * 3.0; + float y = screen_pos.y * 3.0; + float mask = sin(x * PI) * sin(y * PI) * 0.5 + 0.5; + return vec3(1.0 - mask * 0.15); + } + + return vec3(1.0); +} + +// Simple bloom effect (multi-tap blur approximation) +vec3 applyBloom(vec2 coord, vec3 original) { + if (crt_params.bloom <= 0.0) { + return original; + } + + vec2 texel_size = 1.0 / vec2(crt_params.screen_width, crt_params.screen_height); + vec3 bloom_color = original; + + // Simple 5-tap horizontal blur + for (int i = -2; i <= 2; i++) { + vec2 offset = vec2(float(i) * texel_size.x, 0.0); + vec3 sample_color = texture(color_texture, clamp(coord + offset, vec2(0.0), vec2(1.0))).rgb; + bloom_color += sample_color; + } + + bloom_color /= 6.0; // Average of 5 taps + original + + // Mix original with bloom + return mix(original, bloom_color, crt_params.bloom * 0.3); +} + +void main() { + // Apply curvature distortion first + vec2 curved_coord = applyCurvature(frag_tex_coord); + + // Sample the texture + vec3 rgb = texture(color_texture, curved_coord).rgb; + + // Apply bloom + rgb = applyBloom(curved_coord, rgb); + + // Apply phosphor mask + rgb *= applyMask(curved_coord); + + // Apply scanlines + float scan = scanline(curved_coord.y); + rgb *= scan; + + // Gamma correction + if (crt_params.gamma > 0.0 && crt_params.gamma != 1.0) { + rgb = pow(clamp(rgb, vec3(0.0), vec3(1.0)), vec3(1.0 / crt_params.gamma)); + } + + // Apply brightness adjustment + rgb *= crt_params.brightness; + + // Clamp to valid range and apply alpha + color = vec4(clamp(rgb, vec3(0.0), vec3(1.0)), crt_params.alpha); +} diff --git a/src/video_core/renderer_vulkan/present/filters.cpp b/src/video_core/renderer_vulkan/present/filters.cpp index e9dc2be22..673b1ea8a 100644 --- a/src/video_core/renderer_vulkan/present/filters.cpp +++ b/src/video_core/renderer_vulkan/present/filters.cpp @@ -1,5 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/common_types.h" @@ -12,6 +12,7 @@ #include "video_core/host_shaders/vulkan_present_scaleforce_fp32_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scalefx_fp16_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scalefx_fp32_frag_spv.h" +#include "video_core/host_shaders/vulkan_crt_easymode_frag_spv.h" #include "video_core/renderer_vulkan/present/filters.h" #include "video_core/renderer_vulkan/present/util.h" #include "video_core/renderer_vulkan/vk_shader_util.h" @@ -75,4 +76,9 @@ std::unique_ptr MakeLanczos(const Device& device, VkFormat fram BuildShader(device, PRESENT_LANCZOS_FRAG_SPV)); } +std::unique_ptr MakeCRT(const Device& device, VkFormat frame_format) { + return std::make_unique(device, frame_format, CreateBilinearSampler(device), + BuildShader(device, VULKAN_CRT_EASYMODE_FRAG_SPV)); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/filters.h b/src/video_core/renderer_vulkan/present/filters.h index a69abf209..d7d047cb1 100644 --- a/src/video_core/renderer_vulkan/present/filters.h +++ b/src/video_core/renderer_vulkan/present/filters.h @@ -1,5 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -17,5 +17,6 @@ std::unique_ptr MakeLanczos(const Device& device, VkFormat fram std::unique_ptr MakeGaussian(const Device& device, VkFormat frame_format); std::unique_ptr MakeScaleForce(const Device& device, VkFormat frame_format); std::unique_ptr MakeScaleFx(const Device& device, VkFormat frame_format); +std::unique_ptr MakeCRT(const Device& device, VkFormat frame_format); } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp index 46f477c82..2f576b997 100644 --- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp @@ -1,5 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "core/frontend/framebuffer_layout.h" @@ -13,7 +13,7 @@ #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h" -#include "common/settings.h" +#include "common/settings.h" namespace Vulkan { @@ -92,18 +92,51 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area); cmdbuf.ClearAttachments({clear_attachment}, {clear_rect}); + const auto current_scaling_filter = Settings::values.scaling_filter.GetValue(); + const bool is_crt_enabled = current_scaling_filter == Settings::ScalingFilter::CRTEasyMode || + current_scaling_filter == Settings::ScalingFilter::CRTRoyale; + for (size_t i = 0; i < layer_count; i++) { cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipelines[i]); cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PresentPushConstants), &push_constants[i]); - - if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Lanczos) { + // Push Lanczos quality if using Lanczos filter + if (current_scaling_filter == Settings::ScalingFilter::Lanczos && !is_crt_enabled) { const s32 lanczos_a = Settings::values.lanczos_quality.GetValue(); cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(PresentPushConstants), sizeof(s32), &lanczos_a); } + // Push CRT parameters if CRT filter is enabled + if (is_crt_enabled) { + struct CRTPushConstants { + float scanline_strength; + float curvature; + float gamma; + float bloom; + int mask_type; + float brightness; + float alpha; + float screen_width; + float screen_height; + } crt_constants; + + crt_constants.scanline_strength = Settings::values.crt_scanline_strength.GetValue(); + crt_constants.curvature = Settings::values.crt_curvature.GetValue(); + crt_constants.gamma = Settings::values.crt_gamma.GetValue(); + crt_constants.bloom = Settings::values.crt_bloom.GetValue(); + crt_constants.mask_type = Settings::values.crt_mask_type.GetValue(); + crt_constants.brightness = Settings::values.crt_brightness.GetValue(); + crt_constants.alpha = Settings::values.crt_alpha.GetValue(); + crt_constants.screen_width = static_cast(render_area.width); + crt_constants.screen_height = static_cast(render_area.height); + + cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, + sizeof(PresentPushConstants) + sizeof(s32), + sizeof(CRTPushConstants), &crt_constants); + } + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, descriptor_sets[i], {}); cmdbuf.Draw(4, 1, 0, 0); @@ -127,8 +160,11 @@ void WindowAdaptPass::CreateDescriptorSetLayout() { } void WindowAdaptPass::CreatePipelineLayout() { - - std::array ranges{}; + // Support up to 3 push constant ranges: + // 0: PresentPushConstants (vertex shader) + // 1: Lanczos quality (fragment shader) - optional + // 2: CRT parameters (fragment shader) - optional + std::array ranges{}; // Range 0: The existing constants for the Vertex Shader ranges[0] = { @@ -137,13 +173,33 @@ void WindowAdaptPass::CreatePipelineLayout() { .size = sizeof(PresentPushConstants), }; - // Range 1: Our new constant for the Fragment Shader + // Range 1: Lanczos quality for the Fragment Shader ranges[1] = { .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, .offset = sizeof(PresentPushConstants), .size = sizeof(s32), }; + // Range 2: CRT parameters for the Fragment Shader + // Offset after PresentPushConstants + Lanczos (if used) + // CRT constants: 8 floats + 1 int = 36 bytes + struct CRTPushConstants { + float scanline_strength; + float curvature; + float gamma; + float bloom; + int mask_type; + float brightness; + float alpha; + float screen_width; + float screen_height; + }; + ranges[2] = { + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .offset = sizeof(PresentPushConstants) + sizeof(s32), + .size = sizeof(CRTPushConstants), + }; + pipeline_layout = device.GetLogical().CreatePipelineLayout(VkPipelineLayoutCreateInfo{ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 07d329872..d59da892c 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -1,7 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/settings.h" #include "video_core/framebuffer_config.h" #include "video_core/present.h" #include "video_core/renderer_vulkan/present/filters.h" @@ -50,6 +51,10 @@ void BlitScreen::SetWindowAdaptPass() { case Settings::ScalingFilter::ScaleFx: window_adapt = MakeScaleFx(device, swapchain_view_format); break; + case Settings::ScalingFilter::CRTEasyMode: + case Settings::ScalingFilter::CRTRoyale: + window_adapt = MakeCRT(device, swapchain_view_format); + break; case Settings::ScalingFilter::Fsr: case Settings::ScalingFilter::Fsr2: case Settings::ScalingFilter::Bilinear: