[Impeller] reland: directly encode blit commands for Metal. (flutter/engine#52819)

Fixes bad interaction with render pass clear patch, which potentially created an active blit and render pass encoder at the same time. Make sure that we start/finish the render pass before we start the blit pass.
This commit is contained in:
Jonah Williams 2024-05-14 15:32:19 -07:00 committed by GitHub
parent c16a2409e5
commit ff5ea29080
8 changed files with 203 additions and 345 deletions

View File

@ -42656,8 +42656,6 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/gles/texture_gles.cc + ../../
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/texture_gles.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/command_buffer_mtl.h + ../../../flutter/LICENSE
@ -45531,8 +45529,6 @@ FILE: ../../../flutter/impeller/renderer/backend/gles/texture_gles.cc
FILE: ../../../flutter/impeller/renderer/backend/gles/texture_gles.h
FILE: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/command_buffer_mtl.h

View File

@ -8,8 +8,6 @@ impeller_component("metal") {
sources = [
"allocator_mtl.h",
"allocator_mtl.mm",
"blit_command_mtl.h",
"blit_command_mtl.mm",
"blit_pass_mtl.h",
"blit_pass_mtl.mm",
"command_buffer_mtl.h",

View File

@ -1,66 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_BLIT_COMMAND_MTL_H_
#define FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_BLIT_COMMAND_MTL_H_
#include <Metal/Metal.h>
#include "impeller/base/backend_cast.h"
#include "impeller/renderer/blit_command.h"
namespace impeller {
/// Mixin for dispatching Metal commands.
struct BlitEncodeMTL : BackendCast<BlitEncodeMTL, BlitCommand> {
virtual ~BlitEncodeMTL();
virtual std::string GetLabel() const = 0;
[[nodiscard]] virtual bool Encode(
id<MTLBlitCommandEncoder> encoder) const = 0;
};
struct BlitCopyTextureToTextureCommandMTL
: public BlitCopyTextureToTextureCommand,
public BlitEncodeMTL {
~BlitCopyTextureToTextureCommandMTL() override;
std::string GetLabel() const override;
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
};
struct BlitCopyTextureToBufferCommandMTL
: public BlitCopyTextureToBufferCommand,
public BlitEncodeMTL {
~BlitCopyTextureToBufferCommandMTL() override;
std::string GetLabel() const override;
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
};
struct BlitGenerateMipmapCommandMTL : public BlitGenerateMipmapCommand,
public BlitEncodeMTL {
~BlitGenerateMipmapCommandMTL() override;
std::string GetLabel() const override;
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
};
struct BlitCopyBufferToTextureCommandMTL
: public BlitCopyBufferToTextureCommand,
public BlitEncodeMTL {
~BlitCopyBufferToTextureCommandMTL() override;
std::string GetLabel() const override;
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
};
} // namespace impeller
#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_BLIT_COMMAND_MTL_H_

View File

@ -1,152 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/renderer/backend/metal/blit_command_mtl.h"
#include "impeller/renderer/backend/metal/device_buffer_mtl.h"
#include "impeller/renderer/backend/metal/texture_mtl.h"
namespace impeller {
BlitEncodeMTL::~BlitEncodeMTL() = default;
BlitCopyTextureToTextureCommandMTL::~BlitCopyTextureToTextureCommandMTL() =
default;
std::string BlitCopyTextureToTextureCommandMTL::GetLabel() const {
return label;
}
bool BlitCopyTextureToTextureCommandMTL::Encode(
id<MTLBlitCommandEncoder> encoder) const {
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
if (!source_mtl) {
return false;
}
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
if (!destination_mtl) {
return false;
}
auto source_origin_mtl =
MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
auto source_size_mtl =
MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
auto destination_origin_mtl =
MTLOriginMake(destination_origin.x, destination_origin.y, 0);
[encoder copyFromTexture:source_mtl
sourceSlice:0
sourceLevel:0
sourceOrigin:source_origin_mtl
sourceSize:source_size_mtl
toTexture:destination_mtl
destinationSlice:0
destinationLevel:0
destinationOrigin:destination_origin_mtl];
return true;
};
BlitCopyTextureToBufferCommandMTL::~BlitCopyTextureToBufferCommandMTL() =
default;
std::string BlitCopyTextureToBufferCommandMTL::GetLabel() const {
return label;
}
bool BlitCopyTextureToBufferCommandMTL::Encode(
id<MTLBlitCommandEncoder> encoder) const {
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
if (!source_mtl) {
return false;
}
auto destination_mtl = DeviceBufferMTL::Cast(*destination).GetMTLBuffer();
if (!destination_mtl) {
return false;
}
auto source_origin_mtl =
MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
auto source_size_mtl =
MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
auto destination_bytes_per_pixel =
BytesPerPixelForPixelFormat(source->GetTextureDescriptor().format);
auto destination_bytes_per_row =
source_size_mtl.width * destination_bytes_per_pixel;
auto destination_bytes_per_image =
source_size_mtl.height * destination_bytes_per_row;
[encoder copyFromTexture:source_mtl
sourceSlice:0
sourceLevel:0
sourceOrigin:source_origin_mtl
sourceSize:source_size_mtl
toBuffer:destination_mtl
destinationOffset:destination_offset
destinationBytesPerRow:destination_bytes_per_row
destinationBytesPerImage:destination_bytes_per_image];
return true;
};
BlitCopyBufferToTextureCommandMTL::~BlitCopyBufferToTextureCommandMTL() =
default;
std::string BlitCopyBufferToTextureCommandMTL::GetLabel() const {
return label;
}
bool BlitCopyBufferToTextureCommandMTL::Encode(
id<MTLBlitCommandEncoder> encoder) const {
auto source_mtl = DeviceBufferMTL::Cast(*source.buffer).GetMTLBuffer();
if (!source_mtl) {
return false;
}
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
if (!destination_mtl) {
return false;
}
auto destination_origin_mtl =
MTLOriginMake(destination_region.GetX(), destination_region.GetY(), 0);
auto source_size_mtl = MTLSizeMake(destination_region.GetWidth(),
destination_region.GetHeight(), 1);
auto destination_bytes_per_pixel =
BytesPerPixelForPixelFormat(destination->GetTextureDescriptor().format);
auto source_bytes_per_row =
destination_region.GetWidth() * destination_bytes_per_pixel;
[encoder copyFromBuffer:source_mtl
sourceOffset:source.range.offset
sourceBytesPerRow:source_bytes_per_row
sourceBytesPerImage:
0 // 0 for 2D textures according to
// https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400752-copyfrombuffer
sourceSize:source_size_mtl
toTexture:destination_mtl
destinationSlice:slice
destinationLevel:0
destinationOrigin:destination_origin_mtl];
return true;
};
BlitGenerateMipmapCommandMTL::~BlitGenerateMipmapCommandMTL() = default;
std::string BlitGenerateMipmapCommandMTL::GetLabel() const {
return label;
}
bool BlitGenerateMipmapCommandMTL::Encode(
id<MTLBlitCommandEncoder> encoder) const {
return TextureMTL::Cast(*texture).GenerateMipmap(encoder);
};
} // namespace impeller

View File

@ -7,7 +7,6 @@
#include <Metal/Metal.h>
#include "impeller/renderer/backend/metal/blit_command_mtl.h"
#include "impeller/renderer/blit_pass.h"
namespace impeller {
@ -20,10 +19,14 @@ class BlitPassMTL final : public BlitPass {
private:
friend class CommandBufferMTL;
std::vector<std::unique_ptr<BlitEncodeMTL>> commands_;
id<MTLBlitCommandEncoder> encoder_ = nil;
id<MTLCommandBuffer> buffer_ = nil;
std::string label_;
bool is_valid_ = false;
bool is_metal_trace_active_ = false;
// Many parts of the codebase will start writing to a render pass but
// never submit them. This boolean is used to track if a submit happened
// so that in the dtor we can always ensure the render pass is finished.
mutable bool did_finish_encoding_ = false;
explicit BlitPassMTL(id<MTLCommandBuffer> buffer);
@ -37,8 +40,6 @@ class BlitPassMTL final : public BlitPass {
bool EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const override;
bool EncodeCommands(id<MTLBlitCommandEncoder> pass) const;
// |BlitPass|
bool OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
std::shared_ptr<Texture> destination,

View File

@ -15,12 +15,12 @@
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/core/shader_types.h"
#include "impeller/renderer/backend/metal/blit_command_mtl.h"
#include "impeller/renderer/backend/metal/device_buffer_mtl.h"
#include "impeller/renderer/backend/metal/formats_mtl.h"
#include "impeller/renderer/backend/metal/pipeline_mtl.h"
#include "impeller/renderer/backend/metal/sampler_mtl.h"
#include "impeller/renderer/backend/metal/texture_mtl.h"
#include "impeller/renderer/blit_command.h"
namespace impeller {
@ -29,10 +29,19 @@ BlitPassMTL::BlitPassMTL(id<MTLCommandBuffer> buffer) : buffer_(buffer) {
if (!buffer_) {
return;
}
encoder_ = [buffer_ blitCommandEncoder];
#ifdef IMPELLER_DEBUG
is_metal_trace_active_ =
[[MTLCaptureManager sharedCaptureManager] isCapturing];
#endif // IMPELLER_DEBUG
is_valid_ = true;
}
BlitPassMTL::~BlitPassMTL() = default;
BlitPassMTL::~BlitPassMTL() {
if (!did_finish_encoding_) {
[encoder_ endEncoding];
}
}
bool BlitPassMTL::IsValid() const {
return is_valid_;
@ -42,49 +51,13 @@ void BlitPassMTL::OnSetLabel(std::string label) {
if (label.empty()) {
return;
}
label_ = std::move(label);
[encoder_ setLabel:@(label.c_str())];
}
bool BlitPassMTL::EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const {
TRACE_EVENT0("impeller", "BlitPassMTL::EncodeCommands");
if (!IsValid()) {
return false;
}
auto blit_command_encoder = [buffer_ blitCommandEncoder];
if (!blit_command_encoder) {
return false;
}
if (!label_.empty()) {
[blit_command_encoder setLabel:@(label_.c_str())];
}
// Success or failure, the pass must end. The buffer can only process one pass
// at a time.
fml::ScopedCleanupClosure auto_end(
[blit_command_encoder]() { [blit_command_encoder endEncoding]; });
return EncodeCommands(blit_command_encoder);
}
bool BlitPassMTL::EncodeCommands(id<MTLBlitCommandEncoder> encoder) const {
fml::closure pop_debug_marker = [encoder]() { [encoder popDebugGroup]; };
for (const auto& command : commands_) {
fml::ScopedCleanupClosure auto_pop_debug_marker(pop_debug_marker);
auto label = command->GetLabel();
if (!label.empty()) {
[encoder pushDebugGroup:@(label.c_str())];
} else {
auto_pop_debug_marker.Release();
}
if (!command->Encode(encoder)) {
return false;
}
}
[encoder_ endEncoding];
did_finish_encoding_ = true;
return true;
}
@ -95,14 +68,44 @@ bool BlitPassMTL::OnCopyTextureToTextureCommand(
IRect source_region,
IPoint destination_origin,
std::string label) {
auto command = std::make_unique<BlitCopyTextureToTextureCommandMTL>();
command->label = label;
command->source = std::move(source);
command->destination = std::move(destination);
command->source_region = source_region;
command->destination_origin = destination_origin;
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
if (!source_mtl) {
return false;
}
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
if (!destination_mtl) {
return false;
}
auto source_origin_mtl =
MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
auto source_size_mtl =
MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
auto destination_origin_mtl =
MTLOriginMake(destination_origin.x, destination_origin.y, 0);
#ifdef IMPELLER_DEBUG
if (is_metal_trace_active_) {
[encoder_ pushDebugGroup:@(label.c_str())];
}
#endif // IMPELLER_DEBUG
[encoder_ copyFromTexture:source_mtl
sourceSlice:0
sourceLevel:0
sourceOrigin:source_origin_mtl
sourceSize:source_size_mtl
toTexture:destination_mtl
destinationSlice:0
destinationLevel:0
destinationOrigin:destination_origin_mtl];
#ifdef IMPELLER_DEBUG
if (is_metal_trace_active_) {
[encoder_ popDebugGroup];
}
#endif // IMPELLER_DEBUG
commands_.emplace_back(std::move(command));
return true;
}
@ -113,14 +116,48 @@ bool BlitPassMTL::OnCopyTextureToBufferCommand(
IRect source_region,
size_t destination_offset,
std::string label) {
auto command = std::make_unique<BlitCopyTextureToBufferCommandMTL>();
command->label = label;
command->source = std::move(source);
command->destination = std::move(destination);
command->source_region = source_region;
command->destination_offset = destination_offset;
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
if (!source_mtl) {
return false;
}
commands_.emplace_back(std::move(command));
auto destination_mtl = DeviceBufferMTL::Cast(*destination).GetMTLBuffer();
if (!destination_mtl) {
return false;
}
auto source_origin_mtl =
MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
auto source_size_mtl =
MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
auto destination_bytes_per_pixel =
BytesPerPixelForPixelFormat(source->GetTextureDescriptor().format);
auto destination_bytes_per_row =
source_size_mtl.width * destination_bytes_per_pixel;
auto destination_bytes_per_image =
source_size_mtl.height * destination_bytes_per_row;
#ifdef IMPELLER_DEBUG
if (is_metal_trace_active_) {
[encoder_ pushDebugGroup:@(label.c_str())];
}
#endif // IMPELLER_DEBUG
[encoder_ copyFromTexture:source_mtl
sourceSlice:0
sourceLevel:0
sourceOrigin:source_origin_mtl
sourceSize:source_size_mtl
toBuffer:destination_mtl
destinationOffset:destination_offset
destinationBytesPerRow:destination_bytes_per_row
destinationBytesPerImage:destination_bytes_per_image];
#ifdef IMPELLER_DEBUG
if (is_metal_trace_active_) {
[encoder_ popDebugGroup];
}
#endif // IMPELLER_DEBUG
return true;
}
@ -130,26 +167,67 @@ bool BlitPassMTL::OnCopyBufferToTextureCommand(
IRect destination_region,
std::string label,
uint32_t slice) {
auto command = std::make_unique<BlitCopyBufferToTextureCommandMTL>();
command->label = std::move(label);
command->source = std::move(source);
command->destination = std::move(destination);
command->destination_region = destination_region;
command->slice = slice;
auto source_mtl = DeviceBufferMTL::Cast(*source.buffer).GetMTLBuffer();
if (!source_mtl) {
return false;
}
commands_.emplace_back(std::move(command));
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
if (!destination_mtl) {
return false;
}
auto destination_origin_mtl =
MTLOriginMake(destination_region.GetX(), destination_region.GetY(), 0);
auto source_size_mtl = MTLSizeMake(destination_region.GetWidth(),
destination_region.GetHeight(), 1);
auto destination_bytes_per_pixel =
BytesPerPixelForPixelFormat(destination->GetTextureDescriptor().format);
auto source_bytes_per_row =
destination_region.GetWidth() * destination_bytes_per_pixel;
#ifdef IMPELLER_DEBUG
if (is_metal_trace_active_) {
[encoder_ pushDebugGroup:@(label.c_str())];
}
#endif // IMPELLER_DEBUG
[encoder_
copyFromBuffer:source_mtl
sourceOffset:source.range.offset
sourceBytesPerRow:source_bytes_per_row
sourceBytesPerImage:
0 // 0 for 2D textures according to
// https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400752-copyfrombuffer
sourceSize:source_size_mtl
toTexture:destination_mtl
destinationSlice:slice
destinationLevel:0
destinationOrigin:destination_origin_mtl];
#ifdef IMPELLER_DEBUG
if (is_metal_trace_active_) {
[encoder_ popDebugGroup];
}
#endif // IMPELLER_DEBUG
return true;
}
// |BlitPass|
bool BlitPassMTL::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
std::string label) {
auto command = std::make_unique<BlitGenerateMipmapCommandMTL>();
command->label = label;
command->texture = std::move(texture);
commands_.emplace_back(std::move(command));
return true;
#ifdef IMPELLER_DEBUG
if (is_metal_trace_active_) {
[encoder_ pushDebugGroup:@(label.c_str())];
}
#endif // IMPELLER_DEBUG
auto result = TextureMTL::Cast(*texture).GenerateMipmap(encoder_);
#ifdef IMPELLER_DEBUG
if (is_metal_trace_active_) {
[encoder_ popDebugGroup];
}
#endif // IMPELLER_DEBUG
return result;
}
} // namespace impeller

View File

@ -66,11 +66,13 @@ TEST_P(BlitPassTest, BlitPassesForMatchingFormats) {
TextureDescriptor src_desc;
src_desc.format = PixelFormat::kR8G8B8A8UNormInt;
src_desc.size = {100, 100};
src_desc.storage_mode = StorageMode::kHostVisible;
auto src = context->GetResourceAllocator()->CreateTexture(src_desc);
TextureDescriptor dst_format;
dst_format.format = PixelFormat::kR8G8B8A8UNormInt;
dst_format.size = {100, 100};
dst_format.storage_mode = StorageMode::kHostVisible;
auto dst = context->GetResourceAllocator()->CreateTexture(dst_format);
EXPECT_TRUE(blit_pass->AddCopy(src, dst));

View File

@ -306,43 +306,6 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas,
return true;
}
// The texture needs to be cleared to transparent black so that linearly
// samplex rotated/skewed glyphs do not grab uninitialized data.
bool ClearTextureToTransparentBlack(Context& context,
HostBuffer& host_buffer,
std::shared_ptr<CommandBuffer>& cmd_buffer,
std::shared_ptr<BlitPass>& blit_pass,
std::shared_ptr<Texture>& texture) {
// The R8/A8 textures used for certain glyphs is not supported as color
// attachments in most graphics drivers. To be safe, just do a CPU clear
// for these.
if (texture->GetTextureDescriptor().format ==
context.GetCapabilities()->GetDefaultGlyphAtlasFormat()) {
size_t byte_size =
texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
BufferView buffer_view =
host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
byte_size);
buffer_view.buffer->Flush();
return blit_pass->AddCopy(buffer_view, texture);
}
// In all other cases, we can use a render pass to clear to a transparent
// color.
ColorAttachment attachment;
attachment.clear_color = Color::BlackTransparent();
attachment.load_action = LoadAction::kClear;
attachment.store_action = StoreAction::kStore;
attachment.texture = texture;
RenderTarget render_target;
render_target.SetColorAttachment(attachment, 0u);
auto render_pass = cmd_buffer->CreateRenderPass(render_target);
return render_pass->EncodeCommands();
}
std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
Context& context,
GlyphAtlas::Type type,
@ -359,13 +322,6 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
if (font_glyph_map.empty()) {
return last_atlas;
}
std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
fml::ScopedCleanupClosure closure([&]() {
blit_pass->EncodeCommands(context.GetResourceAllocator());
context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
});
// ---------------------------------------------------------------------------
// Step 1: Determine if the atlas type and font glyph pairs are compatible
@ -394,8 +350,7 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
// ---------------------------------------------------------------------------
// Step 2: Determine if the additional missing glyphs can be appended to the
// existing bitmap without recreating the atlas. This requires that
// the type is identical.
// existing bitmap without recreating the atlas.
// ---------------------------------------------------------------------------
std::vector<Rect> glyph_positions;
if (CanAppendToExistingAtlas(last_atlas, new_glyphs, glyph_positions,
@ -412,6 +367,14 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
last_atlas->AddTypefaceGlyphPosition(new_glyphs[i], glyph_positions[i]);
}
std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
fml::ScopedCleanupClosure closure([&]() {
blit_pass->EncodeCommands(context.GetResourceAllocator());
context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
});
// ---------------------------------------------------------------------------
// Step 4a: Draw new font-glyph pairs into the a host buffer and encode
// the uploads into the blit pass.
@ -502,8 +465,46 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
new_texture->SetLabel("GlyphAtlas");
ClearTextureToTransparentBlack(context, host_buffer, cmd_buffer, blit_pass,
new_texture);
std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
std::shared_ptr<BlitPass> blit_pass;
// The R8/A8 textures used for certain glyphs is not supported as color
// attachments in most graphics drivers. To be safe, just do a CPU clear
// for these.
if (type == GlyphAtlas::Type::kAlphaBitmap) {
size_t byte_size =
new_texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
BufferView buffer_view =
host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
byte_size);
buffer_view.buffer->Flush();
blit_pass = cmd_buffer->CreateBlitPass();
blit_pass->AddCopy(buffer_view, new_texture);
} else {
// In all other cases, we can use a render pass to clear to a transparent
// color.
ColorAttachment attachment;
attachment.clear_color = Color::BlackTransparent();
attachment.load_action = LoadAction::kClear;
attachment.store_action = StoreAction::kStore;
attachment.texture = new_texture;
RenderTarget render_target;
render_target.SetColorAttachment(attachment, 0u);
auto render_pass = cmd_buffer->CreateRenderPass(render_target);
render_pass->EncodeCommands();
blit_pass = cmd_buffer->CreateBlitPass();
}
FML_DCHECK(!!blit_pass);
fml::ScopedCleanupClosure closure([&]() {
blit_pass->EncodeCommands(context.GetResourceAllocator());
context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
});
if (!UpdateAtlasBitmap(*glyph_atlas, blit_pass, host_buffer, new_texture,
font_glyph_pairs)) {
return nullptr;