Browse Source

LibWeb: Use stack to represent blit/sample corners commands state

...instead of allocating separate BorderRadiusCornerClipper for each
executed sample/blit commands pair.

With this change a vector of BorderRadiusCornerClipper has far fewer
items. For example on twitter profile page its size goes down from
~3000 to ~3 items.
Aliaksandr Kalenik 1 năm trước cách đây
mục cha
commit
0eeae7ff24

+ 11 - 9
Userland/Libraries/LibWeb/Painting/CommandExecutorCPU.cpp

@@ -453,21 +453,23 @@ CommandResult CommandExecutorCPU::draw_triangle_wave(Gfx::IntPoint const& p1, Gf
     return CommandResult::Continue;
 }
 
-CommandResult CommandExecutorCPU::sample_under_corners(u32 id, CornerRadii const& corner_radii, Gfx::IntRect const& border_rect, CornerClip corner_clip)
+void CommandExecutorCPU::prepare_to_execute(size_t corner_clip_max_depth)
 {
-    if (id >= m_corner_clippers.size())
-        m_corner_clippers.resize(id + 1);
+    m_corner_clippers_stack.ensure_capacity(corner_clip_max_depth);
+}
 
-    auto clipper = BorderRadiusCornerClipper::create(corner_radii, border_rect.to_type<DevicePixels>(), corner_clip);
-    m_corner_clippers[id] = clipper.release_value();
-    m_corner_clippers[id]->sample_under_corners(painter());
+CommandResult CommandExecutorCPU::sample_under_corners([[maybe_unused]] u32 id, CornerRadii const& corner_radii, Gfx::IntRect const& border_rect, CornerClip corner_clip)
+{
+    auto clipper = BorderRadiusCornerClipper::create(corner_radii, border_rect.to_type<DevicePixels>(), corner_clip).release_value();
+    clipper->sample_under_corners(painter());
+    m_corner_clippers_stack.append(clipper);
     return CommandResult::Continue;
 }
 
-CommandResult CommandExecutorCPU::blit_corner_clipping(u32 id)
+CommandResult CommandExecutorCPU::blit_corner_clipping([[maybe_unused]] u32 id)
 {
-    m_corner_clippers[id]->blit_corner_clipping(painter());
-    m_corner_clippers[id] = nullptr;
+    auto clipper = m_corner_clippers_stack.take_last();
+    clipper->blit_corner_clipping(painter());
     return CommandResult::Continue;
 }
 

+ 3 - 1
Userland/Libraries/LibWeb/Painting/CommandExecutorCPU.h

@@ -49,6 +49,8 @@ public:
     bool needs_prepare_glyphs_texture() const override { return false; }
     void prepare_glyph_texture(HashMap<Gfx::Font const*, HashTable<u32>> const&) override {};
 
+    virtual void prepare_to_execute(size_t corner_clip_max_depth) override;
+
     bool needs_update_immutable_bitmap_texture_cache() const override { return false; }
     void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&) override {};
 
@@ -56,7 +58,7 @@ public:
 
 private:
     Gfx::Bitmap& m_target_bitmap;
-    Vector<RefPtr<BorderRadiusCornerClipper>> m_corner_clippers;
+    Vector<RefPtr<BorderRadiusCornerClipper>> m_corner_clippers_stack;
 
     struct StackingContext {
         MaybeOwned<Gfx::Painter> painter;

+ 1 - 1
Userland/Libraries/LibWeb/Painting/CommandExecutorGPU.cpp

@@ -429,7 +429,7 @@ void CommandExecutorGPU::prepare_glyph_texture(HashMap<Gfx::Font const*, HashTab
     AccelGfx::GlyphAtlas::the().update(unique_glyphs);
 }
 
-void CommandExecutorGPU::prepare_to_execute()
+void CommandExecutorGPU::prepare_to_execute([[maybe_unused]] size_t corner_clip_max_depth)
 {
     m_context.activate();
 }

+ 1 - 1
Userland/Libraries/LibWeb/Painting/CommandExecutorGPU.h

@@ -50,7 +50,7 @@ public:
     virtual bool needs_prepare_glyphs_texture() const override { return true; }
     void prepare_glyph_texture(HashMap<Gfx::Font const*, HashTable<u32>> const&) override;
 
-    virtual void prepare_to_execute() override;
+    virtual void prepare_to_execute(size_t corner_clip_max_depth) override;
 
     bool needs_update_immutable_bitmap_texture_cache() const override { return true; }
     void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&) override;

+ 1 - 1
Userland/Libraries/LibWeb/Painting/CommandList.cpp

@@ -78,7 +78,7 @@ void CommandList::mark_unnecessary_commands()
 
 void CommandList::execute(CommandExecutor& executor)
 {
-    executor.prepare_to_execute();
+    executor.prepare_to_execute(m_corner_clip_max_depth);
 
     if (executor.needs_prepare_glyphs_texture()) {
         HashMap<Gfx::Font const*, HashTable<u32>> unique_glyphs;

+ 5 - 1
Userland/Libraries/LibWeb/Painting/CommandList.h

@@ -86,7 +86,7 @@ public:
     virtual bool would_be_fully_clipped_by_painter(Gfx::IntRect) const = 0;
     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 void prepare_to_execute() { }
+    virtual void prepare_to_execute([[maybe_unused]] size_t corner_clip_max_depth) { }
     virtual bool needs_update_immutable_bitmap_texture_cache() const = 0;
     virtual void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&) = 0;
 };
@@ -99,6 +99,9 @@ public:
     void mark_unnecessary_commands();
     void execute(CommandExecutor&);
 
+    size_t corner_clip_max_depth() const { return m_corner_clip_max_depth; }
+    void set_corner_clip_max_depth(size_t depth) { m_corner_clip_max_depth = depth; }
+
 private:
     struct CommandListItem {
         Optional<i32> scroll_frame_id;
@@ -106,6 +109,7 @@ private:
         bool skip { false };
     };
 
+    size_t m_corner_clip_max_depth { 0 };
     AK::SegmentedVector<CommandListItem, 512> m_commands;
 };
 

+ 2 - 0
Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp

@@ -28,6 +28,8 @@ void RecordingPainter::append(Command&& command)
 void RecordingPainter::sample_under_corners(u32 id, CornerRadii corner_radii, Gfx::IntRect border_rect, CornerClip corner_clip)
 {
     m_corner_clip_state_stack.append({ id, border_rect });
+    if (m_corner_clip_state_stack.size() > commands_list().corner_clip_max_depth())
+        commands_list().set_corner_clip_max_depth(m_corner_clip_state_stack.size());
     append(SampleUnderCorners {
         id,
         corner_radii,