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

Commit fd668af

Browse files
author
Jonah Williams
authored
[Impeller] use render pass to clear glyph atlas texture to transparent black. (#52791)
Alternative to #52746 Work towards flutter/flutter#138798 If possible, use a render pass to clear texture to transparent black. The goal is to reduce the CPU cost for larger atlases.
1 parent 0de6701 commit fd668af

File tree

3 files changed

+66
-15
lines changed

3 files changed

+66
-15
lines changed

impeller/renderer/backend/gles/blit_command_gles.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ bool BlitCopyBufferToTextureCommandGLES::Encode(
276276
0u, // border
277277
data.external_format, // external format
278278
data.type, // type
279-
tex_data // data
279+
nullptr // data
280280
);
281281
texture_gles.MarkSliceInitialized(slice);
282282
}

impeller/renderer/blit_pass_unittests.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,29 @@ TEST_P(BlitPassTest, ChecksInvalidSliceParameters) {
104104
std::nullopt, "", /*slice=*/0));
105105
}
106106

107+
TEST_P(BlitPassTest, CanBlitSmallRegionToUninitializedTexture) {
108+
auto context = GetContext();
109+
auto cmd_buffer = context->CreateCommandBuffer();
110+
auto blit_pass = cmd_buffer->CreateBlitPass();
111+
112+
TextureDescriptor dst_format;
113+
dst_format.storage_mode = StorageMode::kDevicePrivate;
114+
dst_format.format = PixelFormat::kR8G8B8A8UNormInt;
115+
dst_format.size = {1000, 1000};
116+
auto dst = context->GetResourceAllocator()->CreateTexture(dst_format);
117+
118+
DeviceBufferDescriptor src_format;
119+
src_format.size = 4;
120+
src_format.storage_mode = StorageMode::kHostVisible;
121+
auto src = context->GetResourceAllocator()->CreateBuffer(src_format);
122+
123+
ASSERT_TRUE(dst);
124+
125+
EXPECT_TRUE(blit_pass->AddCopy(DeviceBuffer::AsBufferView(src), dst,
126+
IRect::MakeLTRB(0, 0, 1, 1), "", /*slice=*/0));
127+
EXPECT_TRUE(blit_pass->EncodeCommands(GetContext()->GetResourceAllocator()));
128+
EXPECT_TRUE(context->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok());
129+
}
130+
107131
} // namespace testing
108132
} // namespace impeller

impeller/typographer/backends/skia/typographer_context_skia.cc

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,43 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas,
306306
return true;
307307
}
308308

309+
// The texture needs to be cleared to transparent black so that linearly
310+
// samplex rotated/skewed glyphs do not grab uninitialized data.
311+
bool ClearTextureToTransparentBlack(Context& context,
312+
HostBuffer& host_buffer,
313+
std::shared_ptr<CommandBuffer>& cmd_buffer,
314+
std::shared_ptr<BlitPass>& blit_pass,
315+
std::shared_ptr<Texture>& texture) {
316+
// The R8/A8 textures used for certain glyphs is not supported as color
317+
// attachments in most graphics drivers. To be safe, just do a CPU clear
318+
// for these.
319+
if (texture->GetTextureDescriptor().format ==
320+
context.GetCapabilities()->GetDefaultGlyphAtlasFormat()) {
321+
size_t byte_size =
322+
texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
323+
BufferView buffer_view =
324+
host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
325+
326+
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
327+
byte_size);
328+
buffer_view.buffer->Flush();
329+
return blit_pass->AddCopy(buffer_view, texture);
330+
}
331+
// In all other cases, we can use a render pass to clear to a transparent
332+
// color.
333+
ColorAttachment attachment;
334+
attachment.clear_color = Color::BlackTransparent();
335+
attachment.load_action = LoadAction::kClear;
336+
attachment.store_action = StoreAction::kStore;
337+
attachment.texture = texture;
338+
339+
RenderTarget render_target;
340+
render_target.SetColorAttachment(attachment, 0u);
341+
342+
auto render_pass = cmd_buffer->CreateRenderPass(render_target);
343+
return render_pass->EncodeCommands();
344+
}
345+
309346
std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
310347
Context& context,
311348
GlyphAtlas::Type type,
@@ -455,28 +492,18 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
455492
}
456493
descriptor.size = atlas_size;
457494
descriptor.storage_mode = StorageMode::kDevicePrivate;
495+
descriptor.usage = TextureUsage::kShaderRead | TextureUsage::kRenderTarget;
458496
new_texture = context.GetResourceAllocator()->CreateTexture(descriptor);
459497
}
460498

461499
if (!new_texture) {
462500
return nullptr;
463501
}
464-
// The texture needs to be cleared to transparent black so that linearly
465-
// samplex rotated/skewed glyphs do not grab uninitialized data. We could
466-
// instead use a render pass to clear to transparent black, but there are
467-
// more restrictions on what kinds of textures can be bound on GLES.
468-
{
469-
auto bytes =
470-
new_texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
471-
BufferView buffer_view =
472-
host_buffer.Emplace(nullptr, bytes, DefaultUniformAlignment());
473-
474-
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
475-
bytes);
476-
blit_pass->AddCopy(buffer_view, new_texture);
477-
}
478502

479503
new_texture->SetLabel("GlyphAtlas");
504+
505+
ClearTextureToTransparentBlack(context, host_buffer, cmd_buffer, blit_pass,
506+
new_texture);
480507
if (!UpdateAtlasBitmap(*glyph_atlas, blit_pass, host_buffer, new_texture,
481508
font_glyph_pairs)) {
482509
return nullptr;

0 commit comments

Comments
 (0)