summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMacDue <macdue@dueutil.tech>2023-04-10 22:02:16 +0100
committerAndreas Kling <kling@serenityos.org>2023-04-12 07:40:22 +0200
commit790daa475478aaf77bd064ddfa23f61529d1ef29 (patch)
treeafae2af802e64df399276fa61d634e9cd217fca7
parent8283e8b88c5ae78d72894cafa765dc5e0289161d (diff)
downloadserenity-790daa475478aaf77bd064ddfa23f61529d1ef29.zip
LibGfx: Optimize Painter::draw_scaled_bitmap_with_transform()
This now applies clipping to the destination bounding box before painting, which cuts out a load of clipped computation and allows using the faster set_physical_pixel() method. Alongside this it also combines the source_transform and inverse_transform outside the hot loop (which might cut things down a little). The `destination_quad.contains()` check is also removed in favour of just checking if the mapped point is inside the source rect, which takes less work to compute than checking the bounding box. This takes this method down from 98% of the time to 10% of the time when painting Google Street View (with no obvious issues).
-rw-r--r--Userland/Libraries/LibGfx/Painter.cpp34
1 files changed, 17 insertions, 17 deletions
diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp
index c0f5302e26..b5be252aa0 100644
--- a/Userland/Libraries/LibGfx/Painter.cpp
+++ b/Userland/Libraries/LibGfx/Painter.cpp
@@ -2519,11 +2519,11 @@ void Painter::draw_scaled_bitmap_with_transform(IntRect const& dst_rect, Bitmap
} else {
// The painter has an affine transform, we have to draw through it!
- // FIXME: This is *super* inefficient.
+ // FIXME: This is kinda inefficient.
// What we currently do, roughly:
// - Map the destination rect through the context's transform.
// - Compute the bounding rect of the destination quad.
- // - For each point in the computed bounding rect, reverse-map it to a point in the source image.
+ // - For each point in the clipped bounding rect, reverse-map it to a point in the source image.
// - Sample the source image at the computed point.
// - Set or blend (depending on alpha values) one pixel in the canvas.
// - Loop.
@@ -2536,31 +2536,31 @@ void Painter::draw_scaled_bitmap_with_transform(IntRect const& dst_rect, Bitmap
auto destination_quad = transform.map_to_quad(dst_rect.to_type<float>());
auto destination_bounding_rect = destination_quad.bounding_rect().to_rounded<int>();
+ auto source_rect = enclosing_int_rect(src_rect).intersected(bitmap.rect());
Gfx::AffineTransform source_transform;
source_transform.translate(src_rect.x(), src_rect.y());
source_transform.scale(src_rect.width() / dst_rect.width(), src_rect.height() / dst_rect.height());
source_transform.translate(-dst_rect.x(), -dst_rect.y());
- for (int y = destination_bounding_rect.y(); y <= destination_bounding_rect.bottom(); ++y) {
- for (int x = destination_bounding_rect.x(); x <= destination_bounding_rect.right(); ++x) {
- auto destination_point = Gfx::IntPoint { x, y };
- if (!clip_rect().contains(destination_point))
- continue;
- if (!destination_quad.contains(destination_point.to_type<float>()))
- continue;
- auto source_point = source_transform.map(inverse_transform->map(destination_point)).to_rounded<int>();
- if (!bitmap.rect().contains(source_point))
+ auto translated_dest_rect = destination_bounding_rect.translated(translation());
+ auto clipped_bounding_rect = translated_dest_rect.intersected(clip_rect());
+ if (clipped_bounding_rect.is_empty())
+ return;
+
+ auto sample_transform = source_transform.multiply(*inverse_transform);
+ auto start_offset = destination_bounding_rect.location() + (clipped_bounding_rect.location() - translated_dest_rect.location());
+ for (int y = 0; y < clipped_bounding_rect.height(); ++y) {
+ for (int x = 0; x < clipped_bounding_rect.width(); ++x) {
+ auto point = Gfx::IntPoint { x, y };
+ auto sample_point = point + start_offset;
+ auto source_point = sample_transform.map(sample_point).to_rounded<int>();
+ if (!source_rect.contains(source_point))
continue;
auto source_color = bitmap.get_pixel(source_point);
if (source_color.alpha() == 0)
continue;
- if (source_color.alpha() == 255) {
- set_pixel(destination_point, source_color);
- continue;
- }
- auto dst_color = target()->get_pixel(destination_point);
- set_pixel(destination_point, dst_color.blend(source_color));
+ set_physical_pixel(point + clipped_bounding_rect.location(), source_color, true);
}
}
}