LibWeb: Don't produce save & restore commands for scroll frame id change
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run

This allows to substantially decrease display list length and
save/restore churn during painting.

Display list size comparison:

|               | Before | After  |
| ------------- | ------ | ------ |
| basecamp.com  | 19066  | 12248  |
| ladybird.org  | 8878   | 2220   |
| react.dev     | 39074  | 24382  |
This commit is contained in:
Aliaksandr Kalenik 2024-10-11 15:18:39 +02:00 committed by Andreas Kling
parent 4eec621d3a
commit 34261e5490
Notes: github-actions[bot] 2024-10-11 15:27:49 +00:00
7 changed files with 41 additions and 40 deletions

View file

@ -47,12 +47,11 @@ void ClippableAndScrollable::apply_clip(PaintContext& context) const
auto& display_list_recorder = context.display_list_recorder(); auto& display_list_recorder = context.display_list_recorder();
display_list_recorder.save(); display_list_recorder.save();
auto saved_scroll_frame_id = display_list_recorder.scroll_frame_id();
for (auto const& clip_rect : clip_rects) { for (auto const& clip_rect : clip_rects) {
Optional<i32> clip_scroll_frame_id; Optional<i32> clip_scroll_frame_id;
if (clip_rect.enclosing_scroll_frame) if (clip_rect.enclosing_scroll_frame)
clip_scroll_frame_id = clip_rect.enclosing_scroll_frame->id(); clip_scroll_frame_id = clip_rect.enclosing_scroll_frame->id();
display_list_recorder.set_scroll_frame_id(clip_scroll_frame_id); display_list_recorder.push_scroll_frame_id(clip_scroll_frame_id);
auto rect = context.rounded_device_rect(clip_rect.rect).to_type<int>(); auto rect = context.rounded_device_rect(clip_rect.rect).to_type<int>();
auto corner_radii = clip_rect.corner_radii.as_corners(context); auto corner_radii = clip_rect.corner_radii.as_corners(context);
if (corner_radii.has_any_radius()) { if (corner_radii.has_any_radius()) {
@ -60,8 +59,8 @@ void ClippableAndScrollable::apply_clip(PaintContext& context) const
} else { } else {
display_list_recorder.add_clip_rect(rect); display_list_recorder.add_clip_rect(rect);
} }
display_list_recorder.pop_scroll_frame_id();
} }
display_list_recorder.set_scroll_frame_id(saved_scroll_frame_id);
} }
void ClippableAndScrollable::restore_clip(PaintContext& context) const void ClippableAndScrollable::restore_clip(PaintContext& context) const

View file

@ -12,14 +12,16 @@ namespace Web::Painting {
DisplayListRecorder::DisplayListRecorder(DisplayList& command_list) DisplayListRecorder::DisplayListRecorder(DisplayList& command_list)
: m_command_list(command_list) : m_command_list(command_list)
{ {
m_state_stack.append(State());
} }
DisplayListRecorder::~DisplayListRecorder() = default; DisplayListRecorder::~DisplayListRecorder() = default;
void DisplayListRecorder::append(Command&& command) void DisplayListRecorder::append(Command&& command)
{ {
m_command_list.append(move(command), state().scroll_frame_id); Optional<i32> scroll_frame_id;
if (!m_scroll_frame_id_stack.is_empty())
scroll_frame_id = m_scroll_frame_id_stack.last();
m_command_list.append(move(command), scroll_frame_id);
} }
void DisplayListRecorder::paint_nested_display_list(RefPtr<DisplayList> display_list, Gfx::IntRect rect) void DisplayListRecorder::paint_nested_display_list(RefPtr<DisplayList> display_list, Gfx::IntRect rect)
@ -261,15 +263,21 @@ void DisplayListRecorder::translate(Gfx::IntPoint delta)
void DisplayListRecorder::save() void DisplayListRecorder::save()
{ {
append(Save {}); append(Save {});
m_state_stack.append(m_state_stack.last());
} }
void DisplayListRecorder::restore() void DisplayListRecorder::restore()
{ {
append(Restore {}); append(Restore {});
}
VERIFY(m_state_stack.size() > 1); void DisplayListRecorder::push_scroll_frame_id(Optional<i32> id)
m_state_stack.take_last(); {
m_scroll_frame_id_stack.append(id);
}
void DisplayListRecorder::pop_scroll_frame_id()
{
(void)m_scroll_frame_id_stack.take_last();
} }
void DisplayListRecorder::push_stacking_context(PushStackingContextParams params) void DisplayListRecorder::push_stacking_context(PushStackingContextParams params)
@ -282,12 +290,12 @@ void DisplayListRecorder::push_stacking_context(PushStackingContextParams params
.matrix = params.transform.matrix, .matrix = params.transform.matrix,
}, },
.clip_path = params.clip_path }); .clip_path = params.clip_path });
m_state_stack.append(State()); m_scroll_frame_id_stack.append({});
} }
void DisplayListRecorder::pop_stacking_context() void DisplayListRecorder::pop_stacking_context()
{ {
m_state_stack.take_last(); (void)m_scroll_frame_id_stack.take_last();
append(PopStackingContext {}); append(PopStackingContext {});
} }

View file

@ -103,15 +103,8 @@ public:
void translate(Gfx::IntPoint delta); void translate(Gfx::IntPoint delta);
void set_scroll_frame_id(Optional<i32> id) void push_scroll_frame_id(Optional<i32> id);
{ void pop_scroll_frame_id();
state().scroll_frame_id = id;
}
Optional<i32> scroll_frame_id() const
{
return state().scroll_frame_id;
}
void save(); void save();
void restore(); void restore();
@ -157,13 +150,7 @@ public:
void append(Command&& command); void append(Command&& command);
private: private:
struct State { Vector<Optional<i32>> m_scroll_frame_id_stack;
Optional<i32> scroll_frame_id;
};
State& state() { return m_state_stack.last(); }
State const& state() const { return m_state_stack.last(); }
Vector<State> m_state_stack;
DisplayList& m_command_list; DisplayList& m_command_list;
}; };

View file

@ -37,15 +37,15 @@ void InlinePaintable::before_paint(PaintContext& context, PaintPhase) const
apply_clip(context); apply_clip(context);
if (scroll_frame_id().has_value()) { if (scroll_frame_id().has_value()) {
context.display_list_recorder().save(); context.display_list_recorder().push_scroll_frame_id(scroll_frame_id().value());
context.display_list_recorder().set_scroll_frame_id(scroll_frame_id().value());
} }
} }
void InlinePaintable::after_paint(PaintContext& context, PaintPhase) const void InlinePaintable::after_paint(PaintContext& context, PaintPhase) const
{ {
if (scroll_frame_id().has_value()) if (scroll_frame_id().has_value()) {
context.display_list_recorder().restore(); context.display_list_recorder().pop_scroll_frame_id();
}
restore_clip(context); restore_clip(context);
} }

View file

@ -477,15 +477,15 @@ BorderRadiiData PaintableBox::normalized_border_radii_data(ShrinkRadiiForBorders
void PaintableBox::apply_scroll_offset(PaintContext& context, PaintPhase) const void PaintableBox::apply_scroll_offset(PaintContext& context, PaintPhase) const
{ {
if (scroll_frame_id().has_value()) { if (scroll_frame_id().has_value()) {
context.display_list_recorder().save(); context.display_list_recorder().push_scroll_frame_id(scroll_frame_id().value());
context.display_list_recorder().set_scroll_frame_id(scroll_frame_id().value());
} }
} }
void PaintableBox::reset_scroll_offset(PaintContext& context, PaintPhase) const void PaintableBox::reset_scroll_offset(PaintContext& context, PaintPhase) const
{ {
if (scroll_frame_id().has_value()) if (scroll_frame_id().has_value()) {
context.display_list_recorder().restore(); context.display_list_recorder().pop_scroll_frame_id();
}
} }
void PaintableBox::apply_clip_overflow_rect(PaintContext& context, PaintPhase phase) const void PaintableBox::apply_clip_overflow_rect(PaintContext& context, PaintPhase phase) const
@ -687,7 +687,7 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
} }
if (own_scroll_frame_id().has_value()) { if (own_scroll_frame_id().has_value()) {
context.display_list_recorder().set_scroll_frame_id(own_scroll_frame_id().value()); context.display_list_recorder().push_scroll_frame_id(own_scroll_frame_id().value());
} }
} }
@ -716,6 +716,10 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
if (should_clip_overflow) { if (should_clip_overflow) {
context.display_list_recorder().restore(); context.display_list_recorder().restore();
if (own_scroll_frame_id().has_value()) {
context.display_list_recorder().pop_scroll_frame_id();
}
} }
} }

View file

@ -31,8 +31,7 @@ void SVGSVGPaintable::before_children_paint(PaintContext& context, PaintPhase ph
PaintableBox::before_children_paint(context, phase); PaintableBox::before_children_paint(context, phase);
if (phase != PaintPhase::Foreground) if (phase != PaintPhase::Foreground)
return; return;
context.display_list_recorder().save(); context.display_list_recorder().push_scroll_frame_id(scroll_frame_id());
context.display_list_recorder().set_scroll_frame_id(scroll_frame_id());
} }
void SVGSVGPaintable::after_children_paint(PaintContext& context, PaintPhase phase) const void SVGSVGPaintable::after_children_paint(PaintContext& context, PaintPhase phase) const
@ -40,7 +39,7 @@ void SVGSVGPaintable::after_children_paint(PaintContext& context, PaintPhase pha
PaintableBox::after_children_paint(context, phase); PaintableBox::after_children_paint(context, phase);
if (phase != PaintPhase::Foreground) if (phase != PaintPhase::Foreground)
return; return;
context.display_list_recorder().restore(); context.display_list_recorder().pop_scroll_frame_id();
} }
static Gfx::FloatMatrix4x4 matrix_with_scaled_translation(Gfx::FloatMatrix4x4 matrix, float scale) static Gfx::FloatMatrix4x4 matrix_with_scaled_translation(Gfx::FloatMatrix4x4 matrix, float scale)

View file

@ -335,8 +335,9 @@ void StackingContext::paint(PaintContext& context) const
if (has_css_transform) { if (has_css_transform) {
paintable_box().apply_clip_overflow_rect(context, PaintPhase::Foreground); paintable_box().apply_clip_overflow_rect(context, PaintPhase::Foreground);
} }
if (paintable().is_paintable_box() && paintable_box().scroll_frame_id().has_value()) if (paintable().is_paintable_box() && paintable_box().scroll_frame_id().has_value()) {
context.display_list_recorder().set_scroll_frame_id(*paintable_box().scroll_frame_id()); context.display_list_recorder().push_scroll_frame_id(*paintable_box().scroll_frame_id());
}
context.display_list_recorder().push_stacking_context(push_stacking_context_params); context.display_list_recorder().push_stacking_context(push_stacking_context_params);
if (paintable().is_paintable_box()) { if (paintable().is_paintable_box()) {
@ -353,6 +354,9 @@ void StackingContext::paint(PaintContext& context) const
paint_internal(context); paint_internal(context);
context.display_list_recorder().pop_stacking_context(); context.display_list_recorder().pop_stacking_context();
if (paintable().is_paintable_box() && paintable_box().scroll_frame_id().has_value()) {
context.display_list_recorder().pop_scroll_frame_id();
}
if (has_css_transform) if (has_css_transform)
paintable_box().clear_clip_overflow_rect(context, PaintPhase::Foreground); paintable_box().clear_clip_overflow_rect(context, PaintPhase::Foreground);
context.display_list_recorder().restore(); context.display_list_recorder().restore();