Procházet zdrojové kódy

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.
Aliaksandr Kalenik před 1 rokem
rodič
revize
a1c8fb10fa

+ 34 - 0
Userland/Libraries/LibAccelGfx/Painter.cpp

@@ -9,6 +9,7 @@
 #include <LibAccelGfx/GL.h>
 #include <LibAccelGfx/Painter.h>
 #include <LibGfx/Color.h>
+#include <LibGfx/ImmutableBitmap.h>
 #include <LibGfx/Painter.h>
 
 namespace AccelGfx {
@@ -136,6 +137,8 @@ void main() {
 }
 )";
 
+HashMap<u32, GL::Texture> s_immutable_bitmap_texture_cache;
+
 OwnPtr<Painter> 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<float>(), bitmap, src_rect.to_type<float>(), 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<float>(), immutable_bitmap, src_rect.to_type<float>(), 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<u32, Gfx::ImmutableBitmap const*>& 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);
+    }
+}
+
 }

+ 5 - 0
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<Gfx::Font const*, HashTable<u32>> 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<u32, Gfx::ImmutableBitmap const*>&);
+
 private:
     Context& m_context;
 

+ 3 - 0
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<Gfx::Font const*, HashTable<u32>> const&) override {};
 
+    bool needs_update_immutable_bitmap_texture_cache() const override { return false; }
+    void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&) override {};
+
     PaintingCommandExecutorCPU(Gfx::Bitmap& bitmap);
 
 private:

+ 6 - 1
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<Gfx::Font const*,
     painter().prepare_glyph_texture(unique_glyphs);
 }
 
+void PaintingCommandExecutorGPU::update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>& immutable_bitmaps)
+{
+    painter().update_immutable_bitmap_texture_cache(immutable_bitmaps);
+}
+
 }

+ 3 - 0
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<Gfx::Font const*, HashTable<u32>> const&) override;
 
+    bool needs_update_immutable_bitmap_texture_cache() const override { return true; }
+    void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&) override;
+
     PaintingCommandExecutorGPU(Gfx::Bitmap& bitmap);
     ~PaintingCommandExecutorGPU() override;
 

+ 11 - 0
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<u32, Gfx::ImmutableBitmap const*> immutable_bitmaps;
+        for (auto const& command : m_painting_commands) {
+            if (command.has<DrawScaledImmutableBitmap>()) {
+                auto const& immutable_bitmap = command.get<DrawScaledImmutableBitmap>().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++];

+ 3 - 0
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<Gfx::Font const*, HashTable<u32>> const& unique_glyphs) = 0;
+
+    virtual bool needs_update_immutable_bitmap_texture_cache() const = 0;
+    virtual void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&) = 0;
 };
 
 class RecordingPainter {