From 4080af8ebdb2a10fa7d10bbea903419b561effa1 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Mon, 13 May 2024 14:33:34 -0700 Subject: [PATCH 1/5] Re-add kBase, but keep kNearest as the default. --- impeller/core/formats.h | 20 +++++++++--- impeller/core/sampler_descriptor.h | 5 +++ impeller/display_list/dl_dispatcher.cc | 1 + impeller/entity/contents/text_contents.cc | 5 +++ .../renderer/backend/gles/sampler_gles.cc | 31 +++++++++++-------- impeller/renderer/backend/metal/formats_mtl.h | 2 ++ impeller/renderer/backend/vulkan/formats_vk.h | 1 + impeller/renderer/renderer_unittests.cc | 5 +-- 8 files changed, 51 insertions(+), 19 deletions(-) diff --git a/impeller/core/formats.h b/impeller/core/formats.h index aa859b45f6818..5b0751454b0bf 100644 --- a/impeller/core/formats.h +++ b/impeller/core/formats.h @@ -9,7 +9,6 @@ #include #include #include -#include #include "flutter/fml/hash_combine.h" #include "flutter/fml/logging.h" @@ -404,19 +403,32 @@ struct Viewport { } }; +/// @brief Describes how the texture should be sampled when the texture +/// is being shrunk (minified) or expanded (magnified) to fit to +/// the sample point. enum class MinMagFilter { /// Select nearest to the sample point. Most widely supported. kNearest, + /// Select two points and linearly interpolate between them. Some formats /// may not support this. kLinear, }; +/// @brief Options for selecting and filtering between mipmap levels. enum class MipFilter { - /// Sample from the nearest mip level. + /// @brief The texture is sampled as if it only had a single mipmap level. + /// + /// All samples are read from level 0. + kBase, + + /// @brief The nearst mipmap level is selected. kNearest, - /// Sample from the two nearest mip levels and linearly interpolate between - /// them. + + /// @brief Sample from the two nearest mip levels and linearly interpolate. + /// + /// If the filter falls between levels, both levels are sampled, and + /// their results linearly interpolated between levels. kLinear, }; diff --git a/impeller/core/sampler_descriptor.h b/impeller/core/sampler_descriptor.h index 0e92745ec311f..2fe15f6b0faa2 100644 --- a/impeller/core/sampler_descriptor.h +++ b/impeller/core/sampler_descriptor.h @@ -15,6 +15,11 @@ class Context; struct SamplerDescriptor final : public Comparable { MinMagFilter min_filter = MinMagFilter::kNearest; MinMagFilter mag_filter = MinMagFilter::kNearest; + + // TODO(https://github.com/flutter/flutter/issues/148253): + // `MipFilter::kNearest` is the default value for mip filters, as it + // cooresponds with the framework's `FilterQuality.low`. If we ever change the + // default filter quality, we should update this function to match. MipFilter mip_filter = MipFilter::kNearest; SamplerAddressMode width_address_mode = SamplerAddressMode::kClampToEdge; diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index e9ae7fd6f424e..f62aeab1c23b0 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -119,6 +119,7 @@ static impeller::SamplerDescriptor ToSamplerDescriptor( switch (options) { case flutter::DlImageSampling::kNearestNeighbor: desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kNearest; + desc.mip_filter = impeller::MipFilter::kBase; desc.label = "Nearest Sampler"; break; case flutter::DlImageSampling::kLinear: diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index 645d0c46ac62f..0e3c2383fdda4 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -125,6 +125,11 @@ bool TextContents::Render(const ContentContext& renderer, sampler_desc.min_filter = MinMagFilter::kLinear; sampler_desc.mag_filter = MinMagFilter::kLinear; } + + // TODO(https://github.com/flutter/flutter/issues/148253): + // `MipFilter::kNearest` is the default value for mip filters, as it + // cooresponds with the framework's `FilterQuality.low`. If we ever change the + // default filter quality, we should update this function to match. sampler_desc.mip_filter = MipFilter::kNearest; FS::BindGlyphAtlasSampler( diff --git a/impeller/renderer/backend/gles/sampler_gles.cc b/impeller/renderer/backend/gles/sampler_gles.cc index 292db944bbb03..a14e21ace0def 100644 --- a/impeller/renderer/backend/gles/sampler_gles.cc +++ b/impeller/renderer/backend/gles/sampler_gles.cc @@ -16,19 +16,20 @@ SamplerGLES::SamplerGLES(SamplerDescriptor desc) : Sampler(std::move(desc)) {} SamplerGLES::~SamplerGLES() = default; +// TODO(https://github.com/flutter/flutter/issues/148253): `MipFilter::kNearest` +// is the default value for mip filters, as it cooresponds with the framework's +// `FilterQuality.low`. If we ever change the default filter quality, we should +// update this function to match. static GLint ToParam(MinMagFilter minmag_filter, - std::optional mip_filter = std::nullopt) { - if (!mip_filter.has_value()) { - switch (minmag_filter) { - case MinMagFilter::kNearest: - return GL_NEAREST; - case MinMagFilter::kLinear: - return GL_LINEAR; - } - FML_UNREACHABLE(); - } - - switch (mip_filter.value()) { + MipFilter mip_filter = MipFilter::kNearest) { + switch (mip_filter) { + case MipFilter::kBase: + switch (minmag_filter) { + case MinMagFilter::kNearest: + return GL_NEAREST; + case MinMagFilter::kLinear: + return GL_LINEAR; + } case MipFilter::kNearest: switch (minmag_filter) { case MinMagFilter::kNearest: @@ -82,7 +83,11 @@ bool SamplerGLES::ConfigureBoundTexture(const TextureGLES& texture, } const auto& desc = GetDescriptor(); - std::optional mip_filter = std::nullopt; + // TODO(https://github.com/flutter/flutter/issues/148253): + // `MipFilter::kNearest` is the default value for mip filters, as it + // cooresponds with the framework's `FilterQuality.low`. If we ever change the + // default filter quality, we should update this function to match. + MipFilter mip_filter = MipFilter::kBase; if (texture.GetTextureDescriptor().mip_count > 1) { mip_filter = desc.mip_filter; } diff --git a/impeller/renderer/backend/metal/formats_mtl.h b/impeller/renderer/backend/metal/formats_mtl.h index 52f55a53543d7..d1a9b0d94e40a 100644 --- a/impeller/renderer/backend/metal/formats_mtl.h +++ b/impeller/renderer/backend/metal/formats_mtl.h @@ -342,6 +342,8 @@ constexpr MTLSamplerMinMagFilter ToMTLSamplerMinMagFilter(MinMagFilter filter) { constexpr MTLSamplerMipFilter ToMTLSamplerMipFilter(MipFilter filter) { switch (filter) { + case MipFilter::kBase: + return MTLSamplerMipFilterNotMipmapped; case MipFilter::kNearest: return MTLSamplerMipFilterNearest; case MipFilter::kLinear: diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index aef50ac84763c..7524e9ef36752 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -222,6 +222,7 @@ constexpr vk::Filter ToVKSamplerMinMagFilter(MinMagFilter filter) { constexpr vk::SamplerMipmapMode ToVKSamplerMipmapMode(MipFilter filter) { switch (filter) { + case MipFilter::kBase: case MipFilter::kNearest: return vk::SamplerMipmapMode::eNearest; case MipFilter::kLinear: diff --git a/impeller/renderer/renderer_unittests.cc b/impeller/renderer/renderer_unittests.cc index fee7436d829ef..fa32f2c685395 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -781,8 +781,9 @@ TEST_P(RendererTest, CanGenerateMipmaps) { bool first_frame = true; auto host_buffer = HostBuffer::Create(context->GetResourceAllocator()); Renderer::RenderCallback callback = [&](RenderTarget& render_target) { - const char* mip_filter_names[] = {"Nearest", "Linear"}; - const MipFilter mip_filters[] = {MipFilter::kNearest, MipFilter::kLinear}; + const char* mip_filter_names[] = {"Base", "Nearest", "Linear"}; + const MipFilter mip_filters[] = {MipFilter::kBase, MipFilter::kNearest, + MipFilter::kLinear}; const char* min_filter_names[] = {"Nearest", "Linear"}; const MinMagFilter min_filters[] = {MinMagFilter::kNearest, MinMagFilter::kLinear}; From 00eb49d4b1a99ee0c6e6f12cfe5a80450ab04dcb Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Mon, 13 May 2024 14:51:01 -0700 Subject: [PATCH 2/5] Inline VK mip translation. --- impeller/renderer/backend/gles/sampler_gles.cc | 2 +- impeller/renderer/backend/vulkan/sampler_vk.cc | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/impeller/renderer/backend/gles/sampler_gles.cc b/impeller/renderer/backend/gles/sampler_gles.cc index a14e21ace0def..ed400fae212fc 100644 --- a/impeller/renderer/backend/gles/sampler_gles.cc +++ b/impeller/renderer/backend/gles/sampler_gles.cc @@ -87,7 +87,7 @@ bool SamplerGLES::ConfigureBoundTexture(const TextureGLES& texture, // `MipFilter::kNearest` is the default value for mip filters, as it // cooresponds with the framework's `FilterQuality.low`. If we ever change the // default filter quality, we should update this function to match. - MipFilter mip_filter = MipFilter::kBase; + MipFilter mip_filter = MipFilter::kNearest; if (texture.GetTextureDescriptor().mip_count > 1) { mip_filter = desc.mip_filter; } diff --git a/impeller/renderer/backend/vulkan/sampler_vk.cc b/impeller/renderer/backend/vulkan/sampler_vk.cc index 2e0946302d5cf..2d7bfe1c0159b 100644 --- a/impeller/renderer/backend/vulkan/sampler_vk.cc +++ b/impeller/renderer/backend/vulkan/sampler_vk.cc @@ -7,6 +7,7 @@ #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/yuv_conversion_vk.h" +#include "vulkan/vulkan_core.h" namespace impeller { @@ -14,8 +15,6 @@ static vk::UniqueSampler CreateSampler( const vk::Device& device, const SamplerDescriptor& desc, const std::shared_ptr& yuv_conversion) { - const auto mip_map = ToVKSamplerMipmapMode(desc.mip_filter); - const auto min_filter = ToVKSamplerMinMagFilter(desc.min_filter); const auto mag_filter = ToVKSamplerMinMagFilter(desc.mag_filter); @@ -36,9 +35,22 @@ static vk::UniqueSampler CreateSampler( sampler_info.addressModeV = address_mode_v; sampler_info.addressModeW = address_mode_w; sampler_info.borderColor = vk::BorderColor::eFloatTransparentBlack; - sampler_info.mipmapMode = mip_map; sampler_info.maxLod = VK_LOD_CLAMP_NONE; + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSamplerCreateInfo.html#_description + switch (desc.mip_filter) { + case MipFilter::kBase: + sampler_info.mipmapMode = vk::SamplerMipmapMode::eNearest; + sampler_info.minLod = sampler_info.maxLod = 0.0f; + break; + case MipFilter::kNearest: + sampler_info.mipmapMode = vk::SamplerMipmapMode::eNearest; + break; + case MipFilter::kLinear: + sampler_info.mipmapMode = vk::SamplerMipmapMode::eLinear; + break; + } + if (yuv_conversion && yuv_conversion->IsValid()) { sampler_chain.get().conversion = yuv_conversion->GetConversion(); From e7f0495a6c0cb9a4e5c986967fa83020a7a4b59b Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Mon, 13 May 2024 15:37:26 -0700 Subject: [PATCH 3/5] ++ --- impeller/entity/contents/text_contents.cc | 7 ++----- impeller/renderer/backend/gles/sampler_gles.cc | 3 ++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index 0e3c2383fdda4..c2818de9fa0e5 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -126,11 +126,8 @@ bool TextContents::Render(const ContentContext& renderer, sampler_desc.mag_filter = MinMagFilter::kLinear; } - // TODO(https://github.com/flutter/flutter/issues/148253): - // `MipFilter::kNearest` is the default value for mip filters, as it - // cooresponds with the framework's `FilterQuality.low`. If we ever change the - // default filter quality, we should update this function to match. - sampler_desc.mip_filter = MipFilter::kNearest; + // No mipmaps for glyph atlas (glyphs are generated at exact scales). + sampler_desc.mip_filter = MipFilter::kBase; FS::BindGlyphAtlasSampler( pass, // command diff --git a/impeller/renderer/backend/gles/sampler_gles.cc b/impeller/renderer/backend/gles/sampler_gles.cc index ed400fae212fc..886af1cb6978d 100644 --- a/impeller/renderer/backend/gles/sampler_gles.cc +++ b/impeller/renderer/backend/gles/sampler_gles.cc @@ -94,7 +94,8 @@ bool SamplerGLES::ConfigureBoundTexture(const TextureGLES& texture, gl.TexParameteri(*target, GL_TEXTURE_MIN_FILTER, ToParam(desc.min_filter, mip_filter)); - gl.TexParameteri(*target, GL_TEXTURE_MAG_FILTER, ToParam(desc.mag_filter)); + gl.TexParameteri(*target, GL_TEXTURE_MAG_FILTER, + ToParam(desc.mag_filter, MipFilter::kBase)); const auto supports_decal_mode = gl.GetCapabilities()->SupportsDecalSamplerAddressMode(); From 5cb53a5ce20b95b7902c5b0ae3beae7f31150737 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Tue, 14 May 2024 09:24:17 -0700 Subject: [PATCH 4/5] Fix GLES rendering. --- .../renderer/backend/gles/sampler_gles.cc | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/impeller/renderer/backend/gles/sampler_gles.cc b/impeller/renderer/backend/gles/sampler_gles.cc index 886af1cb6978d..39e8dcfb67f60 100644 --- a/impeller/renderer/backend/gles/sampler_gles.cc +++ b/impeller/renderer/backend/gles/sampler_gles.cc @@ -4,6 +4,7 @@ #include "impeller/renderer/backend/gles/sampler_gles.h" +#include "GLES3/gl3.h" #include "impeller/base/validation.h" #include "impeller/core/formats.h" #include "impeller/renderer/backend/gles/formats_gles.h" @@ -16,20 +17,20 @@ SamplerGLES::SamplerGLES(SamplerDescriptor desc) : Sampler(std::move(desc)) {} SamplerGLES::~SamplerGLES() = default; -// TODO(https://github.com/flutter/flutter/issues/148253): `MipFilter::kNearest` -// is the default value for mip filters, as it cooresponds with the framework's -// `FilterQuality.low`. If we ever change the default filter quality, we should -// update this function to match. -static GLint ToParam(MinMagFilter minmag_filter, - MipFilter mip_filter = MipFilter::kNearest) { +static GLint ToParam(MinMagFilter minmag_filter) { + switch (minmag_filter) { + case MinMagFilter::kNearest: + return GL_NEAREST; + case MinMagFilter::kLinear: + return GL_LINEAR; + } + FML_UNREACHABLE(); +} + +static GLint ToParam(MinMagFilter minmag_filter, MipFilter mip_filter) { switch (mip_filter) { case MipFilter::kBase: - switch (minmag_filter) { - case MinMagFilter::kNearest: - return GL_NEAREST; - case MinMagFilter::kLinear: - return GL_LINEAR; - } + return ToParam(minmag_filter); case MipFilter::kNearest: switch (minmag_filter) { case MinMagFilter::kNearest: @@ -83,19 +84,18 @@ bool SamplerGLES::ConfigureBoundTexture(const TextureGLES& texture, } const auto& desc = GetDescriptor(); - // TODO(https://github.com/flutter/flutter/issues/148253): - // `MipFilter::kNearest` is the default value for mip filters, as it - // cooresponds with the framework's `FilterQuality.low`. If we ever change the - // default filter quality, we should update this function to match. - MipFilter mip_filter = MipFilter::kNearest; + GLint mag_filter = ToParam(desc.mag_filter); + + // If the texture doesn't have mipmaps, we can't use mip filtering. + GLint min_filter; if (texture.GetTextureDescriptor().mip_count > 1) { - mip_filter = desc.mip_filter; + min_filter = ToParam(desc.min_filter, desc.mip_filter); + } else { + min_filter = ToParam(desc.min_filter); } - gl.TexParameteri(*target, GL_TEXTURE_MIN_FILTER, - ToParam(desc.min_filter, mip_filter)); - gl.TexParameteri(*target, GL_TEXTURE_MAG_FILTER, - ToParam(desc.mag_filter, MipFilter::kBase)); + gl.TexParameteri(*target, GL_TEXTURE_MIN_FILTER, min_filter); + gl.TexParameteri(*target, GL_TEXTURE_MAG_FILTER, mag_filter); const auto supports_decal_mode = gl.GetCapabilities()->SupportsDecalSamplerAddressMode(); From 459759b8cc88654e1f64d36ec9b582cbe5563026 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Tue, 14 May 2024 09:42:31 -0700 Subject: [PATCH 5/5] ++ --- impeller/renderer/backend/gles/sampler_gles.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/impeller/renderer/backend/gles/sampler_gles.cc b/impeller/renderer/backend/gles/sampler_gles.cc index 39e8dcfb67f60..52d5e912420d3 100644 --- a/impeller/renderer/backend/gles/sampler_gles.cc +++ b/impeller/renderer/backend/gles/sampler_gles.cc @@ -4,7 +4,6 @@ #include "impeller/renderer/backend/gles/sampler_gles.h" -#include "GLES3/gl3.h" #include "impeller/base/validation.h" #include "impeller/core/formats.h" #include "impeller/renderer/backend/gles/formats_gles.h"