diff --git a/impeller/renderer/backend/gles/blit_command_gles.cc b/impeller/renderer/backend/gles/blit_command_gles.cc index c7a5de96fa3ed..b3b6d84423a2b 100644 --- a/impeller/renderer/backend/gles/blit_command_gles.cc +++ b/impeller/renderer/backend/gles/blit_command_gles.cc @@ -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); } diff --git a/impeller/renderer/blit_pass_unittests.cc b/impeller/renderer/blit_pass_unittests.cc index 732af99108a1a..e30d89fb049b4 100644 --- a/impeller/renderer/blit_pass_unittests.cc +++ b/impeller/renderer/blit_pass_unittests.cc @@ -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 diff --git a/impeller/typographer/backends/skia/typographer_context_skia.cc b/impeller/typographer/backends/skia/typographer_context_skia.cc index 25f36c73bc05c..35c39a96907d4 100644 --- a/impeller/typographer/backends/skia/typographer_context_skia.cc +++ b/impeller/typographer/backends/skia/typographer_context_skia.cc @@ -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& cmd_buffer, + std::shared_ptr& blit_pass, + std::shared_ptr& 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 TypographerContextSkia::CreateGlyphAtlas( Context& context, GlyphAtlas::Type type, @@ -455,28 +492,18 @@ std::shared_ptr 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;