Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] Conditionally use A8 or R8 format glyph atlas based on capabilities. #50534

Merged
merged 10 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions impeller/aiks/aiks_blur_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ TEST_P(AiksTest, GaussianBlurWithoutDecalSupport) {
FLT_FORWARD(mock_capabilities, old_capabilities, SupportsCompute);
FLT_FORWARD(mock_capabilities, old_capabilities,
SupportsTextureToTextureBlits);
FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultGlyphAtlasFormat);
ASSERT_TRUE(SetCapabilities(mock_capabilities).ok());

auto texture = std::make_shared<Image>(CreateTextureForFixture("boston.jpg"));
Expand Down
6 changes: 5 additions & 1 deletion impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,11 @@ ContentContext::ContentContext(
options_trianglestrip);
srgb_to_linear_filter_pipelines_.CreateDefault(*context_,
options_trianglestrip);
glyph_atlas_pipelines_.CreateDefault(*context_, options);
glyph_atlas_pipelines_.CreateDefault(
*context_, options,
{static_cast<Scalar>(
GetContext()->GetCapabilities()->GetDefaultGlyphAtlasFormat() ==
PixelFormat::kA8UNormInt)});
glyph_atlas_color_pipelines_.CreateDefault(*context_, options);
geometry_color_pipelines_.CreateDefault(*context_, options);
yuv_to_rgb_filter_pipelines_.CreateDefault(*context_, options_trianglestrip);
Expand Down
8 changes: 7 additions & 1 deletion impeller/entity/shaders/glyph_atlas.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ precision mediump float;

uniform f16sampler2D glyph_atlas_sampler;

layout(constant_id = 0) const float use_alpha_color_channel = 1.0;

in highp vec2 v_uv;

IMPELLER_MAYBE_FLAT in f16vec4 v_text_color;
Expand All @@ -16,5 +18,9 @@ out f16vec4 frag_color;

void main() {
f16vec4 value = texture(glyph_atlas_sampler, v_uv);
frag_color = value.aaaa * v_text_color;
if (use_alpha_color_channel == 1.0) {
frag_color = value.aaaa * v_text_color;
} else {
frag_color = value.rrrr * v_text_color;
}
}
11 changes: 11 additions & 0 deletions impeller/renderer/backend/gles/capabilities_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "impeller/renderer/backend/gles/capabilities_gles.h"

#include "impeller/core/formats.h"
#include "impeller/renderer/backend/gles/proc_table_gles.h"

namespace impeller {
Expand Down Expand Up @@ -102,6 +103,12 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
num_shader_binary_formats = value;
}

if (desc->IsES()) {
default_glyph_atlas_format_ = PixelFormat::kA8UNormInt;
} else {
default_glyph_atlas_format_ = PixelFormat::kR8UNormInt;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jason-simmons I think this shoudl be enough to get desktop GL working.

}

supports_framebuffer_fetch_ = desc->HasExtension(kFramebufferFetchExt);

if (desc->HasExtension(kTextureBorderClampExt) ||
Expand Down Expand Up @@ -194,4 +201,8 @@ bool CapabilitiesGLES::IsANGLE() const {
return is_angle_;
}

PixelFormat CapabilitiesGLES::GetDefaultGlyphAtlasFormat() const {
return default_glyph_atlas_format_;
}

} // namespace impeller
5 changes: 5 additions & 0 deletions impeller/renderer/backend/gles/capabilities_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <cstddef>

#include "impeller/base/backend_cast.h"
#include "impeller/core/formats.h"
#include "impeller/core/shader_types.h"
#include "impeller/geometry/size.h"
#include "impeller/renderer/capabilities.h"
Expand Down Expand Up @@ -118,12 +119,16 @@ class CapabilitiesGLES final
// |Capabilities|
PixelFormat GetDefaultDepthStencilFormat() const override;

// |Capabilities|
PixelFormat GetDefaultGlyphAtlasFormat() const override;

private:
bool supports_framebuffer_fetch_ = false;
bool supports_decal_sampler_address_mode_ = false;
bool supports_offscreen_msaa_ = false;
bool supports_implicit_msaa_ = false;
bool is_angle_ = false;
PixelFormat default_glyph_atlas_format_ = PixelFormat::kUnknown;
};

} // namespace impeller
Expand Down
6 changes: 5 additions & 1 deletion impeller/renderer/backend/gles/texture_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ struct TexImage2DData {
external_format = GL_ALPHA;
type = GL_UNSIGNED_BYTE;
break;
case PixelFormat::kR8UNormInt:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GL_RED is ES 3.0 and above only. A8 was chosen based on the ES 2.0 floors cap.

I agree that we should NOT depend on swizzles however. We observed some pretty dire performance cliffs with swizzles on older drivers. Though, to perform a swizzle via GL_TEXTURE_SWIZZLE_ requires ES 3.0 too. So we can't do it on ES 2.0 (and we shouldn't).

I suggest having a kGrayBitmap that maps to the backend native format and have an ifdef in the shader to pick the right format directly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, will do some more digging on that. I thought I observed Skia consistently using red bitmaps but that might just be on newer devices.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏽 go/es2-reference and go/es3-reference might come in handy. I also have Dash docsets for the different versions so checking up flag compatibility is easier. If you use Dash though.

internal_format = GL_RED;
external_format = GL_RED;
type = GL_UNSIGNED_BYTE;
break;
case PixelFormat::kR8G8B8A8UNormInt:
case PixelFormat::kB8G8R8A8UNormInt:
case PixelFormat::kR8G8B8A8UNormIntSRGB:
Expand Down Expand Up @@ -161,7 +166,6 @@ struct TexImage2DData {
break;
case PixelFormat::kUnknown:
case PixelFormat::kD32FloatS8UInt:
case PixelFormat::kR8UNormInt:
case PixelFormat::kR8G8UNormInt:
case PixelFormat::kB10G10R10XRSRGB:
case PixelFormat::kB10G10R10XR:
Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/metal/context_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) {
.SetSupportsComputeSubgroups(DeviceSupportsComputeSubgroups(device))
.SetSupportsReadFromResolve(true)
.SetSupportsDeviceTransientTextures(true)
.SetDefaultGlyphAtlasFormat(PixelFormat::kA8UNormInt)
.Build();
}

Expand Down
4 changes: 4 additions & 0 deletions impeller/renderer/backend/vulkan/capabilities_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -484,4 +484,8 @@ bool CapabilitiesVK::HasOptionalDeviceExtension(
optional_device_extensions_.end();
}

PixelFormat CapabilitiesVK::GetDefaultGlyphAtlasFormat() const {
return PixelFormat::kR8UNormInt;
}

} // namespace impeller
3 changes: 3 additions & 0 deletions impeller/renderer/backend/vulkan/capabilities_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ class CapabilitiesVK final : public Capabilities,
// |Capabilities|
PixelFormat GetDefaultDepthStencilFormat() const override;

// |Capabilities|
PixelFormat GetDefaultGlyphAtlasFormat() const override;

private:
bool validations_enabled_ = false;
std::map<std::string, std::set<std::string>> exts_;
Expand Down
9 changes: 0 additions & 9 deletions impeller/renderer/backend/vulkan/debug_report_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,6 @@ DebugReportVK::Result DebugReportVK::OnDebugCallback(
return Result::kContinue;
}

// This is a real error but we can't fix it due to our headers being too
// old. More more details see:
// https://vulkan.lunarg.com/doc/view/1.3.224.1/mac/1.3-extensions/vkspec.html#VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465
// This validation error currently only trips on macOS due to the use of
// texture swizzles.
if (data->messageIdNumber == static_cast<int32_t>(0x82ae5050)) {
return Result::kContinue;
}

std::vector<std::pair<std::string, std::string>> items;

items.emplace_back("Severity", vk::to_string(severity));
Expand Down
23 changes: 20 additions & 3 deletions impeller/renderer/capabilities.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

#include "impeller/renderer/capabilities.h"
#include "impeller/core/formats.h"

namespace impeller {

Expand Down Expand Up @@ -74,10 +75,16 @@ class StandardCapabilities final : public Capabilities {
return default_depth_stencil_format_;
}

// |Capabilities|
bool SupportsDeviceTransientTextures() const override {
return supports_device_transient_textures_;
}

// |Capabilities|
PixelFormat GetDefaultGlyphAtlasFormat() const override {
return default_glyph_atlas_format_;
}

private:
StandardCapabilities(bool supports_offscreen_msaa,
bool supports_ssbo,
Expand All @@ -91,7 +98,8 @@ class StandardCapabilities final : public Capabilities {
bool supports_device_transient_textures,
PixelFormat default_color_format,
PixelFormat default_stencil_format,
PixelFormat default_depth_stencil_format)
PixelFormat default_depth_stencil_format,
PixelFormat default_glyph_atlas_format)
: supports_offscreen_msaa_(supports_offscreen_msaa),
supports_ssbo_(supports_ssbo),
supports_buffer_to_texture_blits_(supports_buffer_to_texture_blits),
Expand All @@ -105,7 +113,8 @@ class StandardCapabilities final : public Capabilities {
supports_device_transient_textures_(supports_device_transient_textures),
default_color_format_(default_color_format),
default_stencil_format_(default_stencil_format),
default_depth_stencil_format_(default_depth_stencil_format) {}
default_depth_stencil_format_(default_depth_stencil_format),
default_glyph_atlas_format_(default_glyph_atlas_format) {}

friend class CapabilitiesBuilder;

Expand All @@ -122,6 +131,7 @@ class StandardCapabilities final : public Capabilities {
PixelFormat default_color_format_ = PixelFormat::kUnknown;
PixelFormat default_stencil_format_ = PixelFormat::kUnknown;
PixelFormat default_depth_stencil_format_ = PixelFormat::kUnknown;
PixelFormat default_glyph_atlas_format_ = PixelFormat::kUnknown;

StandardCapabilities(const StandardCapabilities&) = delete;

Expand Down Expand Up @@ -207,6 +217,12 @@ CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsDeviceTransientTextures(
return *this;
}

CapabilitiesBuilder& CapabilitiesBuilder::SetDefaultGlyphAtlasFormat(
PixelFormat value) {
default_glyph_atlas_format_ = value;
return *this;
}

std::unique_ptr<Capabilities> CapabilitiesBuilder::Build() {
return std::unique_ptr<StandardCapabilities>(new StandardCapabilities( //
supports_offscreen_msaa_, //
Expand All @@ -221,7 +237,8 @@ std::unique_ptr<Capabilities> CapabilitiesBuilder::Build() {
supports_device_transient_textures_, //
default_color_format_.value_or(PixelFormat::kUnknown), //
default_stencil_format_.value_or(PixelFormat::kUnknown), //
default_depth_stencil_format_.value_or(PixelFormat::kUnknown) //
default_depth_stencil_format_.value_or(PixelFormat::kUnknown), //
default_glyph_atlas_format_.value_or(PixelFormat::kUnknown) //
));
}

Expand Down
9 changes: 9 additions & 0 deletions impeller/renderer/capabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ class Capabilities {
/// format was found.
virtual PixelFormat GetDefaultDepthStencilFormat() const = 0;

/// @brief Returns the default pixel format for the alpha bitmap glyph atlas.
///
/// Some backends may use Red channel while others use grey. This
/// should not have any impact
virtual PixelFormat GetDefaultGlyphAtlasFormat() const = 0;

protected:
Capabilities();

Expand Down Expand Up @@ -145,6 +151,8 @@ class CapabilitiesBuilder {

CapabilitiesBuilder& SetSupportsDeviceTransientTextures(bool value);

CapabilitiesBuilder& SetDefaultGlyphAtlasFormat(PixelFormat value);

std::unique_ptr<Capabilities> Build();

private:
Expand All @@ -161,6 +169,7 @@ class CapabilitiesBuilder {
std::optional<PixelFormat> default_color_format_ = std::nullopt;
std::optional<PixelFormat> default_stencil_format_ = std::nullopt;
std::optional<PixelFormat> default_depth_stencil_format_ = std::nullopt;
std::optional<PixelFormat> default_glyph_atlas_format_ = std::nullopt;

CapabilitiesBuilder(const CapabilitiesBuilder&) = delete;

Expand Down
21 changes: 15 additions & 6 deletions impeller/renderer/capabilities_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,40 @@ CAPABILITY_TEST(SupportsDeviceTransientTextures, false);

TEST(CapabilitiesTest, DefaultColorFormat) {
auto defaults = CapabilitiesBuilder().Build();
ASSERT_EQ(defaults->GetDefaultColorFormat(), PixelFormat::kUnknown);
EXPECT_EQ(defaults->GetDefaultColorFormat(), PixelFormat::kUnknown);
auto mutated = CapabilitiesBuilder()
.SetDefaultColorFormat(PixelFormat::kB10G10R10A10XR)
.Build();
ASSERT_EQ(mutated->GetDefaultColorFormat(), PixelFormat::kB10G10R10A10XR);
EXPECT_EQ(mutated->GetDefaultColorFormat(), PixelFormat::kB10G10R10A10XR);
}

TEST(CapabilitiesTest, DefaultStencilFormat) {
auto defaults = CapabilitiesBuilder().Build();
ASSERT_EQ(defaults->GetDefaultStencilFormat(), PixelFormat::kUnknown);
EXPECT_EQ(defaults->GetDefaultStencilFormat(), PixelFormat::kUnknown);
auto mutated = CapabilitiesBuilder()
.SetDefaultStencilFormat(PixelFormat::kS8UInt)
.Build();
ASSERT_EQ(mutated->GetDefaultStencilFormat(), PixelFormat::kS8UInt);
EXPECT_EQ(mutated->GetDefaultStencilFormat(), PixelFormat::kS8UInt);
}

TEST(CapabilitiesTest, DefaultDepthStencilFormat) {
auto defaults = CapabilitiesBuilder().Build();
ASSERT_EQ(defaults->GetDefaultDepthStencilFormat(), PixelFormat::kUnknown);
EXPECT_EQ(defaults->GetDefaultDepthStencilFormat(), PixelFormat::kUnknown);
auto mutated = CapabilitiesBuilder()
.SetDefaultDepthStencilFormat(PixelFormat::kD32FloatS8UInt)
.Build();
ASSERT_EQ(mutated->GetDefaultDepthStencilFormat(),
EXPECT_EQ(mutated->GetDefaultDepthStencilFormat(),
PixelFormat::kD32FloatS8UInt);
}

TEST(CapabilitiesTest, DefaultGlyphAtlasFormat) {
auto defaults = CapabilitiesBuilder().Build();
EXPECT_EQ(defaults->GetDefaultGlyphAtlasFormat(), PixelFormat::kUnknown);
auto mutated = CapabilitiesBuilder()
.SetDefaultGlyphAtlasFormat(PixelFormat::kA8UNormInt)
.Build();
EXPECT_EQ(mutated->GetDefaultGlyphAtlasFormat(), PixelFormat::kA8UNormInt);
}

} // namespace testing
} // namespace impeller
1 change: 1 addition & 0 deletions impeller/renderer/testing/mocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ class MockCapabilities : public Capabilities {
MOCK_METHOD(PixelFormat, GetDefaultColorFormat, (), (const, override));
MOCK_METHOD(PixelFormat, GetDefaultStencilFormat, (), (const, override));
MOCK_METHOD(PixelFormat, GetDefaultDepthStencilFormat, (), (const, override));
MOCK_METHOD(PixelFormat, GetDefaultGlyphAtlasFormat, (), (const, override));
};

class MockCommandQueue : public CommandQueue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "impeller/typographer/backends/skia/typeface_skia.h"
#include "impeller/typographer/rectangle_packer.h"
#include "impeller/typographer/typographer_context.h"
#include "include/core/SkColor.h"
#include "include/core/SkSize.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkFont.h"
Expand Down Expand Up @@ -220,7 +222,9 @@ static std::shared_ptr<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,

switch (atlas.GetType()) {
case GlyphAtlas::Type::kAlphaBitmap:
image_info = SkImageInfo::MakeA8(atlas_size.width, atlas_size.height);
image_info =
SkImageInfo::MakeA8(SkISize{static_cast<int32_t>(atlas_size.width),
static_cast<int32_t>(atlas_size.height)});
break;
case GlyphAtlas::Type::kColorBitmap:
image_info =
Expand Down Expand Up @@ -466,7 +470,7 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
PixelFormat format;
switch (type) {
case GlyphAtlas::Type::kAlphaBitmap:
format = PixelFormat::kA8UNormInt;
format = context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
break;
case GlyphAtlas::Type::kColorBitmap:
format = PixelFormat::kR8G8B8A8UNormInt;
Expand Down
7 changes: 4 additions & 3 deletions impeller/typographer/backends/stb/typographer_context_stb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -516,11 +516,12 @@ std::shared_ptr<GlyphAtlas> TypographerContextSTB::CreateGlyphAtlas(
PixelFormat format;
switch (type) {
case GlyphAtlas::Type::kAlphaBitmap:
format = PixelFormat::kA8UNormInt;
format = context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
break;
case GlyphAtlas::Type::kColorBitmap:
format = DISABLE_COLOR_FONT_SUPPORT ? PixelFormat::kA8UNormInt
: PixelFormat::kR8G8B8A8UNormInt;
format = DISABLE_COLOR_FONT_SUPPORT
? context.GetCapabilities()->GetDefaultGlyphAtlasFormat()
: PixelFormat::kR8G8B8A8UNormInt;
break;
}
auto texture = UploadGlyphTextureAtlas(context.GetResourceAllocator(), bitmap,
Expand Down
5 changes: 3 additions & 2 deletions impeller/typographer/glyph_atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <optional>
#include <unordered_map>

#include "flutter/fml/macros.h"
#include "impeller/core/texture.h"
#include "impeller/geometry/rect.h"
#include "impeller/renderer/pipeline.h"
Expand All @@ -33,8 +32,10 @@ class GlyphAtlas {
enum class Type {
//--------------------------------------------------------------------------
/// The glyphs are reprsented at their requested size using only an 8-bit
/// alpha channel.
/// color channel.
///
/// This might be backed by a grey or red single channel texture, depending
/// on the backend capabilities.
kAlphaBitmap,

//--------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion impeller/typographer/typographer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ TEST_P(TypographerTest, LazyAtlasTracksColor) {

lazy_atlas.AddTextFrame(*frame, 1.0f);

// Creates different atlases for color and alpha bitmap.
// Creates different atlases for color and red bitmap.
auto color_atlas = lazy_atlas.CreateOrGetGlyphAtlas(
*GetContext(), GlyphAtlas::Type::kColorBitmap);

Expand Down