From ca4d443de01f9ff0bad88e995741aeeb5dbc5b04 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Sun, 2 Oct 2022 20:39:38 -0700 Subject: [PATCH] [Impeller] Use fast path for CPU generated textures where possible (flutter/engine#36466) --- .../backend/metal/device_buffer_mtl.mm | 1 + .../backends/skia/text_render_context_skia.cc | 115 ++++++++---------- 2 files changed, 50 insertions(+), 66 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm index 67525dde4de..81aa2387c6c 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm @@ -26,6 +26,7 @@ uint8_t* DeviceBufferMTL::OnGetContents() const { if (storage_mode_ != MTLStorageModeShared) { return nullptr; } + return reinterpret_cast(buffer_.contents); } diff --git a/engine/src/flutter/impeller/typographer/backends/skia/text_render_context_skia.cc b/engine/src/flutter/impeller/typographer/backends/skia/text_render_context_skia.cc index 96ef3f68518..9002452427e 100644 --- a/engine/src/flutter/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/engine/src/flutter/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -4,12 +4,14 @@ #include "impeller/typographer/backends/skia/text_render_context_skia.h" +#include #include #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "impeller/base/allocation.h" #include "impeller/renderer/allocator.h" +#include "impeller/renderer/device_buffer.h" #include "impeller/typographer/backends/skia/typeface_skia.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -238,32 +240,59 @@ static void ConvertBitmapToSignedDistanceField(uint8_t* pixels, #undef nearestpt } -static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, - const ISize& atlas_size) { +static std::shared_ptr CreateAtlasTexture( + const std::shared_ptr& allocator, + const GlyphAtlas& atlas, + const ISize& atlas_size) { TRACE_EVENT0("impeller", __FUNCTION__); auto bitmap = std::make_shared(); SkImageInfo image_info; + PixelFormat format; switch (atlas.GetType()) { case GlyphAtlas::Type::kSignedDistanceField: case GlyphAtlas::Type::kAlphaBitmap: + format = PixelFormat::kA8UNormInt; image_info = SkImageInfo::MakeA8(atlas_size.width, atlas_size.height); break; case GlyphAtlas::Type::kColorBitmap: + format = PixelFormat::kR8G8B8A8UNormInt; image_info = SkImageInfo::MakeN32Premul(atlas_size.width, atlas_size.height); break; } - if (!bitmap->tryAllocPixels(image_info)) { + auto row_bytes = + std::max(static_cast(image_info.minRowBytes()), + static_cast(allocator->MinimumBytesPerRow(format))); + + DeviceBufferDescriptor buffer_descriptor; + buffer_descriptor.storage_mode = StorageMode::kHostVisible; + buffer_descriptor.size = image_info.computeByteSize(row_bytes); + + auto buffer = allocator->CreateBuffer(buffer_descriptor); + if (!buffer) { + return nullptr; + } + + auto pixels = reinterpret_cast(buffer->AsBufferView().contents); + if (!pixels) { + FML_LOG(ERROR) << "No pixels"; + return nullptr; + } + + if (!bitmap->installPixels(image_info, pixels, row_bytes)) { + FML_LOG(ERROR) << "No install pixels"; return nullptr; } auto surface = SkSurface::MakeRasterDirect(bitmap->pixmap()); if (!surface) { + FML_LOG(ERROR) << "No surf"; return nullptr; } auto canvas = surface->getCanvas(); if (!canvas) { + FML_LOG(ERROR) << "No canv"; return nullptr; } @@ -294,48 +323,20 @@ static std::shared_ptr CreateAtlasBitmap(const GlyphAtlas& atlas, return true; }); - return bitmap; -} - -static std::shared_ptr UploadGlyphTextureAtlas( - const std::shared_ptr& allocator, - std::shared_ptr bitmap, - const ISize& atlas_size, - PixelFormat format) { - TRACE_EVENT0("impeller", __FUNCTION__); - if (!allocator) { - return nullptr; + if (atlas.GetType() == GlyphAtlas::Type::kSignedDistanceField) { + ConvertBitmapToSignedDistanceField( + reinterpret_cast(bitmap->getPixels()), atlas_size.width, + atlas_size.height); } - FML_DCHECK(bitmap != nullptr); - const auto& pixmap = bitmap->pixmap(); - - TextureDescriptor texture_descriptor; - texture_descriptor.storage_mode = StorageMode::kHostVisible; - texture_descriptor.format = format; - texture_descriptor.size = atlas_size; - - if (pixmap.rowBytes() * pixmap.height() != - texture_descriptor.GetByteSizeOfBaseMipLevel()) { - return nullptr; + { + TRACE_EVENT0("impeller", "Texture Creation/Upload"); + TextureDescriptor texture_descriptor; + texture_descriptor.storage_mode = StorageMode::kHostVisible; + texture_descriptor.format = format; + texture_descriptor.size = atlas_size; + return buffer->AsTexture(*allocator, texture_descriptor, row_bytes); } - - auto texture = allocator->CreateTexture(texture_descriptor); - if (!texture || !texture->IsValid()) { - return nullptr; - } - texture->SetLabel("GlyphAtlas"); - - auto mapping = std::make_shared( - reinterpret_cast(bitmap->getAddr(0, 0)), // data - texture_descriptor.GetByteSizeOfBaseMipLevel(), // size - [bitmap](auto, auto) mutable { bitmap.reset(); } // proc - ); - - if (!texture->SetContents(mapping)) { - return nullptr; - } - return texture; } std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( @@ -386,37 +387,19 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( } // --------------------------------------------------------------------------- - // Step 5: Draw font-glyph pairs in the correct spot in the atlas. + // Step 5: Create a texture and draw font-glyph pairs in the correct spot in + // the atlas. // --------------------------------------------------------------------------- - auto bitmap = CreateAtlasBitmap(*glyph_atlas, atlas_size); - if (!bitmap) { - return nullptr; - } - // --------------------------------------------------------------------------- - // Step 6: Upload the atlas as a texture. - // --------------------------------------------------------------------------- - PixelFormat format; - switch (type) { - case GlyphAtlas::Type::kSignedDistanceField: - ConvertBitmapToSignedDistanceField( - reinterpret_cast(bitmap->getPixels()), atlas_size.width, - atlas_size.height); - case GlyphAtlas::Type::kAlphaBitmap: - format = PixelFormat::kA8UNormInt; - break; - case GlyphAtlas::Type::kColorBitmap: - format = PixelFormat::kR8G8B8A8UNormInt; - break; - } - auto texture = UploadGlyphTextureAtlas(GetContext()->GetResourceAllocator(), - bitmap, atlas_size, format); + auto texture = CreateAtlasTexture(GetContext()->GetResourceAllocator(), + *glyph_atlas, atlas_size); + if (!texture) { return nullptr; } // --------------------------------------------------------------------------- - // Step 7: Record the texture in the glyph atlas. + // Step 6: Record the texture in the glyph atlas. // --------------------------------------------------------------------------- glyph_atlas->SetTexture(std::move(texture));