Bug 17971

Summary: Extreme slowdown for manual convolutions in most vector backends.
Product: cairo Reporter: M Joonas Pihlaja <jpihlaja>
Component: generalAssignee: Carl Worth <cworth>
Status: RESOLVED FIXED QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: normal    
Priority: medium    
Version: 1.8.1   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments: addblur.c convolves with ADD and paint_with_alpha

Description M Joonas Pihlaja 2008-10-08 05:48:19 UTC
Created attachment 19487 [details]
addblur.c convolves with ADD and paint_with_alpha

When simulating a blur effect with OPERATOR_ADD and paint_with_alpha(), the pdf backends suffer from extreme slowdown as the number of convolutions is increased compared to the image backend or the PDF backend of cairo-1.2.4.  The attached mini program addblur.c illustrates the issue for various backends. The issue affects the svg1.1, ps2, ps3, and the pdf backends at least, but not the svg backend when emitting SVG1.2.

The run times below were generated with cairo HEAD at commit 0c777a3e0de0d48289432a3 (similar results can be seen with cairo-1.6.4). After the first few blur levels the times seem to grow exponentially.

0 misc $ time ./addblur pdf 1

real    0m0.376s
user    0m0.348s
sys     0m0.028s
0 misc $ time ./addblur pdf 2

real    0m0.418s
user    0m0.388s
sys     0m0.028s
0 misc $ time ./addblur pdf 3

real    0m0.602s
user    0m0.528s
sys     0m0.072s
0 misc $ time ./addblur pdf 4

real    0m1.334s
user    0m1.080s
sys     0m0.252s
0 misc $ time ./addblur pdf 5

real    0m4.198s
user    0m3.188s
sys     0m0.960s
0 misc $ time ./addblur pdf 6

real    0m15.672s
user    0m11.957s
sys     0m3.712s
0 misc $ time ./addblur pdf 7 

real    1m3.895s
user    0m47.687s
sys     0m15.917s

With cairo-1.2.4 the times were much less sensitive to the blur level:

0 misc $ time ./addblur pdf 1 

real    0m0.395s
user    0m0.336s
sys     0m0.028s
0 misc $ time ./addblur pdf 2

real    0m0.371s
user    0m0.348s
sys     0m0.024s
0 misc $ time ./addblur pdf 3

real    0m0.384s
user    0m0.352s
sys     0m0.016s
0 misc $ time ./addblur pdf 4

real    0m0.380s
user    0m0.364s
sys     0m0.012s
0 misc $ time ./addblur pdf 5

real    0m0.400s
user    0m0.368s
sys     0m0.028s
0 misc $ time ./addblur pdf 6

real    0m0.409s
user    0m0.300s
sys     0m0.100s
0 misc $ time ./addblur pdf 7

real    0m0.450s
user    0m0.400s
sys     0m0.020s
Comment 1 Adrian Johnson 2008-10-12 07:52:30 UTC
In this code you are doing two calls to cairo_paint_with_alpha() then
using the output as the source pattern to do another two calls to
cairo_paint_with_alpha(). This is repeated for each iteration.

When the number of blurs is 1 the following operations are performed:
  Pattern A is a triangle fill
  Pattern B is pattern A painted twice
  Pattern C is pattern B painted twice
  paint C onto the target surface

Due to the use of operators not supported by most vector backends
fallback images will be used which requires
_cairo_meta_surface_acquire_source_image() to be called. In the image backend acquire_source is called 3 times. In the
vector backends acquire_source is called 7 times.

When the number of blurs is 2 the following operations are performed:
  Pattern A is a triangle fill
  Pattern B is pattern A painted twice
  Pattern C is pattern B painted twice
  Pattern D is pattern C painted twice
  paint D onto the target surface

In the image backend acquire_source is called 4 times. In the vector
backends _cairo_meta_surface_acquire_source_image() is called 31
times.

The problem with the vector backends is a result of the way all the
operations are recorded then replayed. The first problem is we do not
yet have copy-on-write in the meta surface. Every time the same meta
surface pattern is painted a copy of the source meta surface is made.

The second problem is every time the same pattern is painted,
_cairo_meta_surface_acquire_source_image() replays the meta surface to
an image surface. All patterns used by this meta surface are also
replayed to the image surface.

So for num blurs = 2, painting pattern D on the target will result in
the following calls to acquire_source:

meta surface	 num calls to acquire source
--------------------------------------------
Pattern D  	              1
Pattern C                     2
Pattern B                     4
Pattern A                     8
The group with the triangle  16
                         ---------
                         total  31

Fixing this requires two things:

- An implementation of copy-on-write for the meta-surface so that we
  know when we are re-using the same pattern.

- Caching the image created by _cairo_meta_surface_acquire_source_image()
  instead of replaying the meta surface to an image every time
  _cairo_meta_surface_acquire_source_image() is called.

The reason the slow down does not occur in 1.2.4 is that in 1.2.4 the
PDF surface does not implement _create_similar. This will cause
cairo_surface_create_similar() to return an image surface instead of a
meta surface.
Comment 2 Chris Wilson 2009-07-04 05:53:43 UTC
meta-surface source snapshotting pushed:

commit 7903c80ee81777bab6eec408c10b2b59330b10f7
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Sat Jul 4 13:50:15 2009 +0100

    [meta] Cache replays when used as a pattern source
    
    Use the cow-snapshotting mechanism to store the meta surface replay (either
    to an image inside acquire_source_image() or to a similar surface during
    clone_similar()).
    
    Fixes Bug 17971 -- Extreme slowdown for manual convolutions in most
    vector backends.
    https://bugs.freedesktop.org/show_bug.cgi?id=17971

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.