mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] use render pass to clear glyph atlas texture to transparent black. (flutter/engine#52791)
Alternative to https://github.com/flutter/engine/pull/52746 Work towards https://github.com/flutter/flutter/issues/138798 If possible, use a render pass to clear texture to transparent black. The goal is to reduce the CPU cost for larger atlases.
This commit is contained in:
parent
f331d37840
commit
12b56a350b
@ -276,7 +276,7 @@ bool BlitCopyBufferToTextureCommandGLES::Encode(
|
||||
0u, // border
|
||||
data.external_format, // external format
|
||||
data.type, // type
|
||||
tex_data // data
|
||||
nullptr // data
|
||||
);
|
||||
texture_gles.MarkSliceInitialized(slice);
|
||||
}
|
||||
|
||||
@ -104,5 +104,29 @@ TEST_P(BlitPassTest, ChecksInvalidSliceParameters) {
|
||||
std::nullopt, "", /*slice=*/0));
|
||||
}
|
||||
|
||||
TEST_P(BlitPassTest, CanBlitSmallRegionToUninitializedTexture) {
|
||||
auto context = GetContext();
|
||||
auto cmd_buffer = context->CreateCommandBuffer();
|
||||
auto blit_pass = cmd_buffer->CreateBlitPass();
|
||||
|
||||
TextureDescriptor dst_format;
|
||||
dst_format.storage_mode = StorageMode::kDevicePrivate;
|
||||
dst_format.format = PixelFormat::kR8G8B8A8UNormInt;
|
||||
dst_format.size = {1000, 1000};
|
||||
auto dst = context->GetResourceAllocator()->CreateTexture(dst_format);
|
||||
|
||||
DeviceBufferDescriptor src_format;
|
||||
src_format.size = 4;
|
||||
src_format.storage_mode = StorageMode::kHostVisible;
|
||||
auto src = context->GetResourceAllocator()->CreateBuffer(src_format);
|
||||
|
||||
ASSERT_TRUE(dst);
|
||||
|
||||
EXPECT_TRUE(blit_pass->AddCopy(DeviceBuffer::AsBufferView(src), dst,
|
||||
IRect::MakeLTRB(0, 0, 1, 1), "", /*slice=*/0));
|
||||
EXPECT_TRUE(blit_pass->EncodeCommands(GetContext()->GetResourceAllocator()));
|
||||
EXPECT_TRUE(context->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok());
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
|
||||
@ -306,6 +306,43 @@ 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,
|
||||
@ -455,28 +492,18 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
|
||||
}
|
||||
descriptor.size = atlas_size;
|
||||
descriptor.storage_mode = StorageMode::kDevicePrivate;
|
||||
descriptor.usage = TextureUsage::kShaderRead | TextureUsage::kRenderTarget;
|
||||
new_texture = context.GetResourceAllocator()->CreateTexture(descriptor);
|
||||
}
|
||||
|
||||
if (!new_texture) {
|
||||
return nullptr;
|
||||
}
|
||||
// The texture needs to be cleared to transparent black so that linearly
|
||||
// samplex rotated/skewed glyphs do not grab uninitialized data. We could
|
||||
// instead use a render pass to clear to transparent black, but there are
|
||||
// more restrictions on what kinds of textures can be bound on GLES.
|
||||
{
|
||||
auto bytes =
|
||||
new_texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
|
||||
BufferView buffer_view =
|
||||
host_buffer.Emplace(nullptr, bytes, DefaultUniformAlignment());
|
||||
|
||||
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
|
||||
bytes);
|
||||
blit_pass->AddCopy(buffer_view, new_texture);
|
||||
}
|
||||
|
||||
new_texture->SetLabel("GlyphAtlas");
|
||||
|
||||
ClearTextureToTransparentBlack(context, host_buffer, cmd_buffer, blit_pass,
|
||||
new_texture);
|
||||
if (!UpdateAtlasBitmap(*glyph_atlas, blit_pass, host_buffer, new_texture,
|
||||
font_glyph_pairs)) {
|
||||
return nullptr;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user