From 0408e26e4cfd3b35d1e126b2bebb003bf42e4a9a Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:03:36 +0000 Subject: [PATCH 01/14] feat: Add Lanczos --- src/common/settings_enums.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index 36dfcc9a7..b50298a55 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -147,7 +147,7 @@ ENUM(NvdecEmulation, Off, Cpu, Gpu); ENUM(ResolutionSetup, Res1_2X, Res3_4X, Res1X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X, Res8X); -ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Fsr, Fsr2, MaxEnum); +ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Lanczos, Fsr, Fsr2, MaxEnum); ENUM(AntiAliasing, None, Fxaa, Smaa, Taa, MaxEnum); From 7a751408a6ec26fc269fedaa8ebfb604f2ff3f16 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:04:38 +0000 Subject: [PATCH 02/14] feat: Add Lanczos --- src/citron/configuration/shared_translation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/citron/configuration/shared_translation.cpp b/src/citron/configuration/shared_translation.cpp index 6d9f9cb1c..5a717047f 100644 --- a/src/citron/configuration/shared_translation.cpp +++ b/src/citron/configuration/shared_translation.cpp @@ -127,6 +127,7 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral()); INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), tr("Determines how sharpened the image will look while using FSR's dynamic contrast.")); + 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.")); @@ -401,6 +402,7 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")), PAIR(ScalingFilter, Bilinear, tr("Bilinear")), PAIR(ScalingFilter, Bicubic, tr("Bicubic")), + PAIR(ScalingFilter, Lanczos, tr("Lanczos")), PAIR(ScalingFilter, Gaussian, tr("Gaussian")), PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")), PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")), From eb5c6ee46b54d7b061c32e25ae985f108d681042 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:05:23 +0000 Subject: [PATCH 03/14] feat: Add Lanczos --- src/citron/configuration/shared_translation.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/citron/configuration/shared_translation.h b/src/citron/configuration/shared_translation.h index be6fa948b..a2c3bdd98 100644 --- a/src/citron/configuration/shared_translation.h +++ b/src/citron/configuration/shared_translation.h @@ -39,6 +39,7 @@ static const std::map scaling_filter_texts_map {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))}, {Settings::ScalingFilter::Gaussian, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))}, + {Settings::ScalingFilter::Lanczos, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Lanczos"))}, {Settings::ScalingFilter::ScaleForce, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))}, {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, From a027fad07229ab1962c8cb287f2034760d24df27 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:06:20 +0000 Subject: [PATCH 04/14] feat: Add Lanczos Frag --- .../host_shaders/present_lanczos.frag | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/video_core/host_shaders/present_lanczos.frag diff --git a/src/video_core/host_shaders/present_lanczos.frag b/src/video_core/host_shaders/present_lanczos.frag new file mode 100644 index 000000000..b832af312 --- /dev/null +++ b/src/video_core/host_shaders/present_lanczos.frag @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#version 460 core + +layout(location = 0) in vec2 frag_tex_coord; +layout(location = 0) out vec4 color; + +layout(binding = 0) uniform sampler2D color_texture; + +// This block defines the variable that will hold our setting value. +// It uses a preprocessor directive to switch between the OpenGL and Vulkan way of doing things. +#ifdef VULKAN +layout(push_constant) uniform LanczosPushConstant { + layout(offset = 128) int u_lanczos_a; +} lanczos_pc; +#else // OpenGL +layout(location = 0) uniform int u_lanczos_a; +#endif + +const float PI = 3.14159265359; + +float sinc(float x) { + if (x == 0.0) { + return 1.0; + } + return sin(PI * x) / (PI * x); +} + +float lanczos_weight(float x, float a) { + if (abs(x) < a) { + return sinc(x) * sinc(x / a); + } + return 0.0; +} + +vec4 textureLanczos(sampler2D ts, vec2 tc) { + // Get the 'a' value from the correct uniform based on the renderer + #ifdef VULKAN + const int a_val = lanczos_pc.u_lanczos_a; + #else + const int a_val = u_lanczos_a; + #endif + const float a = float(a_val); + + // If 'a' is 0 (which it will be by default since we aren't sending a value yet), + // just do a basic sample to avoid errors. + if (a_val == 0) { + return texture(ts, tc); + } + + vec2 tex_size = vec2(textureSize(ts, 0)); + vec2 inv_tex_size = 1.0 / tex_size; + vec2 p = tc * tex_size; + vec2 f = fract(p); + vec2 p_int = p - f; + + vec4 sum = vec4(0.0); + float weight_sum = 0.0; + + const int MAX_A = 4; + for (int y = -MAX_A + 1; y <= MAX_A; ++y) { + if (abs(y) >= a_val) continue; + for (int x = -MAX_A + 1; x <= MAX_A; ++x) { + if (abs(x) >= a_val) continue; + + vec2 offset = vec2(float(x), float(y)); + float w = lanczos_weight(f.x - offset.x, a) * lanczos_weight(f.y - offset.y, a); + + if (w != 0.0) { + sum += texture(ts, (p_int + offset) * inv_tex_size) * w; + weight_sum += w; + } + } + } + + if (weight_sum == 0.0) { + return texture(ts, tc); + } + + return sum / weight_sum; +} + +void main() { + color = textureLanczos(color_texture, frag_tex_coord); +} From 6f2e1f458ddd56cb4358716b478e31b5c8bbdcc5 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:07:03 +0000 Subject: [PATCH 05/14] feat: Add Lanczos --- src/video_core/host_shaders/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 44f8b7f13..9e0b15075 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later set(FIDELITYFX_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/externals/FidelityFX-FSR/ffx-fsr) @@ -42,6 +43,7 @@ set(SHADER_FILES opengl_smaa.glsl pitch_unswizzle.comp present_bicubic.frag + present_lanczos.frag present_gaussian.frag queries_prefix_scan_sum.comp queries_prefix_scan_sum_nosubgroups.comp From c2446eb91e139230bbabd05a781f4b7aa1d0e5ba Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:07:48 +0000 Subject: [PATCH 06/14] feat: Add Lanczos --- src/video_core/renderer_opengl/present/filters.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_core/renderer_opengl/present/filters.h b/src/video_core/renderer_opengl/present/filters.h index 122ab7436..182a764c6 100644 --- a/src/video_core/renderer_opengl/present/filters.h +++ b/src/video_core/renderer_opengl/present/filters.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -11,6 +12,7 @@ namespace OpenGL { std::unique_ptr MakeNearestNeighbor(const Device& device); std::unique_ptr MakeBilinear(const Device& device); std::unique_ptr MakeBicubic(const Device& device); +std::unique_ptr MakeLanczos(const Device& device); std::unique_ptr MakeGaussian(const Device& device); std::unique_ptr MakeScaleForce(const Device& device); From 0202478a373292d736aebda66360cd6f348e14c6 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:08:29 +0000 Subject: [PATCH 07/14] feat: Add Lanczos --- src/video_core/renderer_vulkan/present/filters.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video_core/renderer_vulkan/present/filters.h b/src/video_core/renderer_vulkan/present/filters.h index 6c83726dd..eb9888f07 100644 --- a/src/video_core/renderer_vulkan/present/filters.h +++ b/src/video_core/renderer_vulkan/present/filters.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -12,6 +13,7 @@ class MemoryAllocator; std::unique_ptr MakeNearestNeighbor(const Device& device, VkFormat frame_format); std::unique_ptr MakeBilinear(const Device& device, VkFormat frame_format); std::unique_ptr MakeBicubic(const Device& device, VkFormat frame_format); +std::unique_ptr MakeLanczos(const Device& device, VkFormat frame_format); std::unique_ptr MakeGaussian(const Device& device, VkFormat frame_format); std::unique_ptr MakeScaleForce(const Device& device, VkFormat frame_format); From c0c75e43ad9f7c1d64635f254fd02f2bbbb27ed0 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:09:42 +0000 Subject: [PATCH 08/14] feat: Add Lanczos --- src/video_core/renderer_vulkan/present/filters.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/video_core/renderer_vulkan/present/filters.cpp b/src/video_core/renderer_vulkan/present/filters.cpp index b5e08938e..d57665b96 100644 --- a/src/video_core/renderer_vulkan/present/filters.cpp +++ b/src/video_core/renderer_vulkan/present/filters.cpp @@ -1,9 +1,11 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/common_types.h" #include "video_core/host_shaders/present_bicubic_frag_spv.h" +#include "video_core/host_shaders/present_lanczos_frag_spv.h" #include "video_core/host_shaders/present_gaussian_frag_spv.h" #include "video_core/host_shaders/vulkan_present_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scaleforce_fp16_frag_spv.h" @@ -53,4 +55,9 @@ std::unique_ptr MakeScaleForce(const Device& device, VkFormat f SelectScaleForceShader(device)); } +std::unique_ptr MakeLanczos(const Device& device, VkFormat frame_format) { + return std::make_unique(device, frame_format, CreateNearestNeighborSampler(device), + BuildShader(device, PRESENT_LANCZOS_FRAG_SPV)); +} + } // namespace Vulkan From 7feef45cee72a1fcac1f4e5ffe22b6ace760dc73 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:10:20 +0000 Subject: [PATCH 09/14] feat: Add Lanczos --- src/video_core/renderer_opengl/present/filters.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/video_core/renderer_opengl/present/filters.cpp b/src/video_core/renderer_opengl/present/filters.cpp index 819e5d77f..619583300 100644 --- a/src/video_core/renderer_opengl/present/filters.cpp +++ b/src/video_core/renderer_opengl/present/filters.cpp @@ -1,9 +1,11 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "video_core/host_shaders/opengl_present_frag.h" #include "video_core/host_shaders/opengl_present_scaleforce_frag.h" #include "video_core/host_shaders/present_bicubic_frag.h" +#include "video_core/host_shaders/present_lanczos_frag.h" #include "video_core/host_shaders/present_gaussian_frag.h" #include "video_core/renderer_opengl/present/filters.h" #include "video_core/renderer_opengl/present/util.h" @@ -36,4 +38,9 @@ std::unique_ptr MakeScaleForce(const Device& device) { fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG)); } +std::unique_ptr MakeLanczos(const Device& device) { + return std::make_unique(device, CreateNearestNeighborSampler(), + HostShaders::PRESENT_LANCZOS_FRAG); +} + } // namespace OpenGL From 37bebbea102534251e432cf40a57ff3e74d37934 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:10:57 +0000 Subject: [PATCH 10/14] feat: Add Lanczos --- src/video_core/renderer_opengl/gl_blit_screen.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp index 091b09ef3..e7d249392 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.cpp +++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp @@ -81,6 +81,9 @@ void BlitScreen::CreateWindowAdapt() { case Settings::ScalingFilter::Bicubic: window_adapt = MakeBicubic(device); break; + case Settings::ScalingFilter::Lanczos: + window_adapt = MakeLanczos(device); + break; case Settings::ScalingFilter::Gaussian: window_adapt = MakeGaussian(device); break; From 5fb1a163443ed8dec71dd42070b915a09973ee2a Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:11:27 +0000 Subject: [PATCH 11/14] feat: Add Lanczos --- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 5a1300b40..a1622b077 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -38,6 +38,9 @@ void BlitScreen::SetWindowAdaptPass() { case Settings::ScalingFilter::Bicubic: window_adapt = MakeBicubic(device, swapchain_view_format); break; + case Settings::ScalingFilter::Lanczos: + window_adapt = MakeLanczos(device, swapchain_view_format); + break; case Settings::ScalingFilter::Gaussian: window_adapt = MakeGaussian(device, swapchain_view_format); break; From 5785ae746ef018eb01b064e701d8679f621784f9 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:12:38 +0000 Subject: [PATCH 12/14] feat: Add Lanczos --- .../present/window_adapt_pass.cpp | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) 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 22ffacf11..46f477c82 100644 --- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "core/frontend/framebuffer_layout.h" @@ -12,6 +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" namespace Vulkan { @@ -92,8 +94,16 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s 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, - push_constants[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) { + 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); + } + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, descriptor_sets[i], {}); cmdbuf.Draw(4, 1, 0, 0); @@ -117,20 +127,31 @@ void WindowAdaptPass::CreateDescriptorSetLayout() { } void WindowAdaptPass::CreatePipelineLayout() { - const VkPushConstantRange range{ + + std::array ranges{}; + + // Range 0: The existing constants for the Vertex Shader + ranges[0] = { .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .offset = 0, .size = sizeof(PresentPushConstants), }; + // Range 1: Our new constant for the Fragment Shader + ranges[1] = { + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .offset = sizeof(PresentPushConstants), + .size = sizeof(s32), + }; + pipeline_layout = device.GetLogical().CreatePipelineLayout(VkPipelineLayoutCreateInfo{ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .setLayoutCount = 1, .pSetLayouts = descriptor_set_layout.address(), - .pushConstantRangeCount = 1, - .pPushConstantRanges = &range, + .pushConstantRangeCount = static_cast(ranges.size()), + .pPushConstantRanges = ranges.data(), }); } From 41fc8ee272112e1a72aaa3d3630097263f5f33be Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:13:55 +0000 Subject: [PATCH 13/14] feat: Add Lanczos --- .../renderer_opengl/present/window_adapt_pass.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp index d8b6a11cb..32920400f 100644 --- a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp @@ -64,10 +64,10 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li glViewportIndexedf(0, 0.0f, 0.0f, static_cast(layout.width), static_cast(layout.height)); - glEnableVertexAttribArray(PositionLocation); - glEnableVertexAttribArray(TexCoordLocation); glVertexAttribDivisor(PositionLocation, 0); glVertexAttribDivisor(TexCoordLocation, 0); + glEnableVertexAttribArray(PositionLocation); + glEnableVertexAttribArray(TexCoordLocation); glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE, offsetof(ScreenRectVertex, position)); glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE, @@ -84,7 +84,6 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li glBindSampler(0, sampler.handle); - // Update background color before drawing glClearColor(Settings::values.bg_red.GetValue() / 255.0f, Settings::values.bg_green.GetValue() / 255.0f, Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); @@ -107,6 +106,11 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li break; } + + if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Lanczos) { + glProgramUniform1i(frag.handle, 0, Settings::values.lanczos_quality.GetValue()); + } + glBindTextureUnit(0, textures[i]); glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE, matrices[i].data()); From 19a5cde29939074deb1f81da54cd260cdc8fa449 Mon Sep 17 00:00:00 2001 From: collecting Date: Mon, 6 Oct 2025 02:14:33 +0000 Subject: [PATCH 14/14] feat: Add Lanczos --- src/common/settings.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/common/settings.h b/src/common/settings.h index e7adf61c0..d55de5990 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -348,6 +348,17 @@ struct Values { true, true}; + + SwitchableSetting lanczos_quality{linkage, + 3, // Default value + 2, // Minimum value + 4, // Maximum value + "lanczos_quality", + Category::Renderer, + Specialization::Scalar, + true, + true}; + SwitchableSetting fsr2_quality_mode{linkage, FSR2QualityMode::Quality, // Quality by default FSR2QualityMode::Quality, // Min value