From a1c8fb10faec6f326b59662cde4d23a59a4d9d67 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Fri, 24 Nov 2023 15:00:49 +0100 Subject: [PATCH] LibAccelGfx+LibWeb: Add texture cache for immutable bitmaps This change introduces a texture cache for immutable bitmaps in the GPU painter. The cache is persisted across page repaints, so now, on page scroll repaint, in many cases, we won't need to upload any new textures. Also, if the same image is painted more than once on a page, its texture will only be uploaded once. Generally, the GPU painter works much faster with this change on all pages that have images. --- Userland/Libraries/LibAccelGfx/Painter.cpp | 34 +++++++++++++++++++ Userland/Libraries/LibAccelGfx/Painter.h | 5 +++ .../Painting/PaintingCommandExecutorCPU.h | 3 ++ .../Painting/PaintingCommandExecutorGPU.cpp | 7 +++- .../Painting/PaintingCommandExecutorGPU.h | 3 ++ .../LibWeb/Painting/RecordingPainter.cpp | 11 ++++++ .../LibWeb/Painting/RecordingPainter.h | 3 ++ 7 files changed, 65 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibAccelGfx/Painter.cpp b/Userland/Libraries/LibAccelGfx/Painter.cpp index 4e220f2ca2..864b19e4d3 100644 --- a/Userland/Libraries/LibAccelGfx/Painter.cpp +++ b/Userland/Libraries/LibAccelGfx/Painter.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace AccelGfx { @@ -136,6 +137,8 @@ void main() { } )"; +HashMap s_immutable_bitmap_texture_cache; + OwnPtr Painter::create() { auto& context = Context::the(); @@ -319,6 +322,18 @@ void Painter::draw_scaled_bitmap(Gfx::IntRect const& dest_rect, Gfx::Bitmap cons draw_scaled_bitmap(dest_rect.to_type(), bitmap, src_rect.to_type(), scaling_mode); } +void Painter::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& immutable_bitmap, Gfx::IntRect const& src_rect, ScalingMode scaling_mode) +{ + draw_scaled_immutable_bitmap(dst_rect.to_type(), immutable_bitmap, src_rect.to_type(), scaling_mode); +} + +void Painter::draw_scaled_immutable_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& immutable_bitmap, Gfx::FloatRect const& src_rect, ScalingMode scaling_mode) +{ + auto texture = s_immutable_bitmap_texture_cache.get(immutable_bitmap.id()); + VERIFY(texture.has_value()); + blit_scaled_texture(dst_rect, texture.value(), src_rect, scaling_mode); +} + static Gfx::FloatRect to_texture_space(Gfx::FloatRect rect, Gfx::IntSize image_size) { auto x = rect.x() / image_size.width(); @@ -690,4 +705,23 @@ void Painter::blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture co GL::delete_vertex_array(vao); } +void Painter::update_immutable_bitmap_texture_cache(HashMap& immutable_bitmaps) +{ + for (auto immutable_bitmap_id : s_immutable_bitmap_texture_cache.keys()) { + if (!immutable_bitmaps.contains(immutable_bitmap_id)) { + auto texture = s_immutable_bitmap_texture_cache.get(immutable_bitmap_id).value(); + GL::delete_texture(texture); + s_immutable_bitmap_texture_cache.remove(immutable_bitmap_id); + } + } + + for (auto const& [id, immutable_bitmap] : immutable_bitmaps) { + if (s_immutable_bitmap_texture_cache.contains(id)) + continue; + auto texture = GL::create_texture(); + GL::upload_texture_data(texture, immutable_bitmap->bitmap()); + s_immutable_bitmap_texture_cache.set(id, texture); + } +} + } diff --git a/Userland/Libraries/LibAccelGfx/Painter.h b/Userland/Libraries/LibAccelGfx/Painter.h index e2d71195b4..ef20e8b398 100644 --- a/Userland/Libraries/LibAccelGfx/Painter.h +++ b/Userland/Libraries/LibAccelGfx/Painter.h @@ -57,6 +57,9 @@ public: void draw_scaled_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap const&, Gfx::FloatRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor); void draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const&, Gfx::IntRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor); + void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::IntRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor); + void draw_scaled_immutable_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::FloatRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor); + void prepare_glyph_texture(HashMap> const& unique_glyphs); struct GlyphsTextureKey { @@ -90,6 +93,8 @@ public: void blit_canvas(Gfx::IntRect const& dst_rect, Canvas const&, float opacity = 1.0f); void blit_canvas(Gfx::FloatRect const& dst_rect, Canvas const&, float opacity = 1.0f); + void update_immutable_bitmap_texture_cache(HashMap&); + private: Context& m_context; diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h index 5d089794eb..d5d5f6d5dd 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h @@ -52,6 +52,9 @@ public: bool needs_prepare_glyphs_texture() const override { return false; } void prepare_glyph_texture(HashMap> const&) override {}; + bool needs_update_immutable_bitmap_texture_cache() const override { return false; } + void update_immutable_bitmap_texture_cache(HashMap&) override {}; + PaintingCommandExecutorCPU(Gfx::Bitmap& bitmap); private: diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp index 18df9fe990..f4712d5bf9 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp @@ -67,7 +67,7 @@ CommandResult PaintingCommandExecutorGPU::draw_scaled_bitmap(Gfx::IntRect const& CommandResult PaintingCommandExecutorGPU::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& immutable_bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) { - painter().draw_scaled_bitmap(dst_rect, immutable_bitmap.bitmap(), src_rect, to_accelgfx_scaling_mode(scaling_mode)); + painter().draw_scaled_immutable_bitmap(dst_rect, immutable_bitmap, src_rect, to_accelgfx_scaling_mode(scaling_mode)); return CommandResult::Continue; } @@ -316,4 +316,9 @@ void PaintingCommandExecutorGPU::prepare_glyph_texture(HashMap& immutable_bitmaps) +{ + painter().update_immutable_bitmap_texture_cache(immutable_bitmaps); +} + } diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h index f9eb72556d..fba5fa605b 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h @@ -52,6 +52,9 @@ public: virtual bool needs_prepare_glyphs_texture() const override { return true; } void prepare_glyph_texture(HashMap> const&) override; + bool needs_update_immutable_bitmap_texture_cache() const override { return true; } + void update_immutable_bitmap_texture_cache(HashMap&) override; + PaintingCommandExecutorGPU(Gfx::Bitmap& bitmap); ~PaintingCommandExecutorGPU() override; diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp index eb38d5565f..6261ea2b19 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp @@ -425,6 +425,17 @@ void RecordingPainter::execute(PaintingCommandExecutor& executor) executor.prepare_glyph_texture(unique_glyphs); } + if (executor.needs_update_immutable_bitmap_texture_cache()) { + HashMap immutable_bitmaps; + for (auto const& command : m_painting_commands) { + if (command.has()) { + auto const& immutable_bitmap = command.get().bitmap; + immutable_bitmaps.set(immutable_bitmap->id(), immutable_bitmap.ptr()); + } + } + executor.update_immutable_bitmap_texture_cache(immutable_bitmaps); + } + size_t next_command_index = 0; while (next_command_index < m_painting_commands.size()) { auto& command = m_painting_commands[next_command_index++]; diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h index b1ee715e5e..89cb70bbcc 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h @@ -396,6 +396,9 @@ public: virtual bool needs_prepare_glyphs_texture() const { return false; } virtual void prepare_glyph_texture(HashMap> const& unique_glyphs) = 0; + + virtual bool needs_update_immutable_bitmap_texture_cache() const = 0; + virtual void update_immutable_bitmap_texture_cache(HashMap&) = 0; }; class RecordingPainter {