mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 12:05:15 +00:00
LibWeb: Skip unnecessary sample corner and blit corner commands
Before this change we were recording and executing sample/blit commands for each painting phase, even if there are no painting commands in-between sample and blit that produce result visible on a canvas. This change adds an optimization pass that goes through recorded painting commands list and marks sample and blit commands that could be skipped. Reduces sample and blit corners executing from 17% to 8% on Discord.
This commit is contained in:
parent
c2829ce2a0
commit
b1205f0aa1
Notes:
sideshowbarker
2024-07-17 00:47:29 +09:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/SerenityOS/serenity/commit/b1205f0aa1 Pull-request: https://github.com/SerenityOS/serenity/pull/24140
3 changed files with 48 additions and 4 deletions
|
@ -2164,6 +2164,7 @@ void Navigable::paint(Painting::RecordingPainter& recording_painter, PaintConfig
|
|||
scroll_offsets_by_frame_id[scrollable_frame->id] = scroll_offset;
|
||||
}
|
||||
recording_painter.commands_list().apply_scroll_offsets(scroll_offsets_by_frame_id);
|
||||
recording_painter.commands_list().mark_unnecessary_commands();
|
||||
}
|
||||
|
||||
m_needs_repaint = false;
|
||||
|
|
|
@ -39,6 +39,43 @@ void CommandList::apply_scroll_offsets(Vector<Gfx::IntPoint> const& offsets_by_f
|
|||
}
|
||||
}
|
||||
|
||||
void CommandList::mark_unnecessary_commands()
|
||||
{
|
||||
// The pair sample_under_corners and blit_corner_clipping commands is not needed if there are no painting commands
|
||||
// in between them that produce visible output.
|
||||
struct SampleCornersBlitCornersRange {
|
||||
u32 sample_command_index;
|
||||
bool has_painting_commands_in_between { false };
|
||||
};
|
||||
// Stack of sample_under_corners commands that have not been matched with a blit_corner_clipping command yet.
|
||||
Vector<SampleCornersBlitCornersRange> sample_blit_ranges;
|
||||
for (u32 command_index = 0; command_index < m_commands.size(); ++command_index) {
|
||||
auto const& command = m_commands[command_index].command;
|
||||
if (command.has<SampleUnderCorners>()) {
|
||||
sample_blit_ranges.append({
|
||||
.sample_command_index = command_index,
|
||||
.has_painting_commands_in_between = false,
|
||||
});
|
||||
} else if (command.has<BlitCornerClipping>()) {
|
||||
auto range = sample_blit_ranges.take_last();
|
||||
if (!range.has_painting_commands_in_between) {
|
||||
m_commands[range.sample_command_index].skip = true;
|
||||
m_commands[command_index].skip = true;
|
||||
}
|
||||
} else {
|
||||
// SetClipRect and ClearClipRect commands do not produce visible output
|
||||
auto update_clip_command = command.has<SetClipRect>() || command.has<ClearClipRect>();
|
||||
if (sample_blit_ranges.size() > 0 && !update_clip_command) {
|
||||
// If painting command is found for sample_under_corners command on top of the stack, then all
|
||||
// sample_under_corners commands below should also not be skipped.
|
||||
for (auto& sample_blit_range : sample_blit_ranges)
|
||||
sample_blit_range.has_painting_commands_in_between = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY(sample_blit_ranges.is_empty());
|
||||
}
|
||||
|
||||
void CommandList::execute(CommandExecutor& executor)
|
||||
{
|
||||
executor.prepare_to_execute();
|
||||
|
@ -76,8 +113,12 @@ void CommandList::execute(CommandExecutor& executor)
|
|||
HashTable<u32> skipped_sample_corner_commands;
|
||||
size_t next_command_index = 0;
|
||||
while (next_command_index < m_commands.size()) {
|
||||
auto& command_with_scroll_id = m_commands[next_command_index++];
|
||||
auto& command = command_with_scroll_id.command;
|
||||
if (m_commands[next_command_index].skip) {
|
||||
next_command_index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& command = m_commands[next_command_index++].command;
|
||||
auto bounding_rect = command_bounding_rectangle(command);
|
||||
if (bounding_rect.has_value() && (bounding_rect->is_empty() || executor.would_be_fully_clipped_by_painter(*bounding_rect))) {
|
||||
if (command.has<SampleUnderCorners>()) {
|
||||
|
|
|
@ -96,15 +96,17 @@ public:
|
|||
void append(Command&& command, Optional<i32> scroll_frame_id);
|
||||
|
||||
void apply_scroll_offsets(Vector<Gfx::IntPoint> const& offsets_by_frame_id);
|
||||
void mark_unnecessary_commands();
|
||||
void execute(CommandExecutor&);
|
||||
|
||||
private:
|
||||
struct CommandWithScrollFrame {
|
||||
struct CommandListItem {
|
||||
Optional<i32> scroll_frame_id;
|
||||
Command command;
|
||||
bool skip { false };
|
||||
};
|
||||
|
||||
AK::SegmentedVector<CommandWithScrollFrame, 512> m_commands;
|
||||
AK::SegmentedVector<CommandListItem, 512> m_commands;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue