Skip to content

Commit

Permalink
[Impeller] Use fast path for CPU generated textures where possible (f…
Browse files Browse the repository at this point in the history
  • Loading branch information
dnfield authored Oct 3, 2022
1 parent a7785c4 commit 0e3ceba
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 66 deletions.
1 change: 1 addition & 0 deletions impeller/renderer/backend/metal/device_buffer_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
if (storage_mode_ != MTLStorageModeShared) {
return nullptr;
}

return reinterpret_cast<uint8_t*>(buffer_.contents);
}

Expand Down
115 changes: 49 additions & 66 deletions impeller/typographer/backends/skia/text_render_context_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

#include "impeller/typographer/backends/skia/text_render_context_skia.h"

#include <stdlib.h>
#include <utility>

#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"
Expand Down Expand Up @@ -238,32 +240,59 @@ static void ConvertBitmapToSignedDistanceField(uint8_t* pixels,
#undef nearestpt
}

static std::shared_ptr<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,
const ISize& atlas_size) {
static std::shared_ptr<Texture> CreateAtlasTexture(
const std::shared_ptr<Allocator>& allocator,
const GlyphAtlas& atlas,
const ISize& atlas_size) {
TRACE_EVENT0("impeller", __FUNCTION__);
auto bitmap = std::make_shared<SkBitmap>();
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<uint16_t>(image_info.minRowBytes()),
static_cast<uint16_t>(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<void*>(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;
}

Expand Down Expand Up @@ -294,48 +323,20 @@ static std::shared_ptr<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,
return true;
});

return bitmap;
}

static std::shared_ptr<Texture> UploadGlyphTextureAtlas(
const std::shared_ptr<Allocator>& allocator,
std::shared_ptr<SkBitmap> bitmap,
const ISize& atlas_size,
PixelFormat format) {
TRACE_EVENT0("impeller", __FUNCTION__);
if (!allocator) {
return nullptr;
if (atlas.GetType() == GlyphAtlas::Type::kSignedDistanceField) {
ConvertBitmapToSignedDistanceField(
reinterpret_cast<uint8_t*>(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<fml::NonOwnedMapping>(
reinterpret_cast<const uint8_t*>(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<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
Expand Down Expand Up @@ -386,37 +387,19 @@ std::shared_ptr<GlyphAtlas> 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<uint8_t*>(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));

Expand Down

0 comments on commit 0e3ceba

Please sign in to comment.