[cairo] Bug with paint_with_alpha and perf issues whencompositing with SOURCE
Owen Taylor
otaylor at redhat.com
Tue May 27 09:16:13 PDT 2008
On Tue, 2008-05-27 at 11:27 -0400, Antoine Azar wrote:
> Hi Owen,
>
> Thanks for the informative reply.
>
> > Which doc is this?
>
> The one on cairographics.org:
> http://www.cairographics.org/manual/cairo-cairo-t.html#id2639090
> "A drawing operator that paints the current source everywhere within the
> current clip region using a mask of constant alpha value alpha. The effect
> is similar to cairo_paint(), but the drawing is faded out using the alpha
> value."
>
> > I can sort of see why you think that paint_with_alpha()
> > should be different ... there's an intuitive understanding of
> > the operation as "make the source partially transparent and
> > then paint it"... but that's not how it's defined. It's
> > defined as painting with a uniform mask.
> > And the rendering equations in cairo for masks don't care
> > whether a 50% alpha is 50% alpha from anti-aliasing at the
> > edge of a shape, or from paint_with_alpha().
> >
> > And so, for OPERATOR_SOURCE that means linear interpolation
> > between the source and destination depending on the alpha value.
>
> With this definition, then yes, I would expect the function to set the alpha
> of my source and then paint it on the destination and replace whatever was
> there before.
The cairo operators all have mathematical definitions .. we've tried to
make them "intuitive", but in the end, the mathematical description is
what wins, not intuitive expectation, or even what is useful in a
particular case.
> Right now, we're using this uniform mask both for dimming the
> source AND for compositing with it. As a result, OVER and SOURCE are doing
> exactly the same thing here.
Careful - "something similar to" is not the same thing as "exactly".
Cairo's SOURCE:
(src IN mask) ADD (dest OUT mask)
dest_c = (src_c * mask_a) + (dest_c * (1 - mask_a))
Cairo's OVER:
(src IN mask) OVER dst
dest_c = (src_c * mask_a) + (dest_c * (1 - src_a * mask_a))
^^^^^
So they are the same if and only if the source has uniform alpha=1.0.
(Which is intuitively right... when the source is opaque, SOURCE and
OVER should do the same thing.)
[ The above uses 'mask' as a short-hand for 'mask IN clip' ]
> In the comments in the code, we replace the SOURCE and CLEAR operators by
> this string of other operators ((src IN mask IN clip) ADD (dst OUT (mask IN
> clip))) because backends don't interpret SOURCE and CLEAR in the same way.
> What I propose is to give backends the possibility of supporting those
> operations natively if they can, and if they don't, we'll fallback to pixman
> and do it in a more efficient way than currently.
Backends can of course already special case things however they want-
this is all in the "fallback" code already.
Now, there's maybe a case that the fallback code is a little too
conservative in assuming pixman/RENDER limitations - you could imagine
some sort of "flag" for the the backend that says "pass me through all
operators and I'll implement cairo semantics". But I haven't seen any
evidence that's a real problem here.
I'm dubious that Quartz can do the actual cairo SOURCE semantics
one-pass since they can't be done one-pass with current OpenGL.
> > In terms of the performance: there's an obvious optimization
> > missing where we create a temporary surface for mask IN clip
> > even when there is no surface clip (see
> > _create_composite_mask_pattern())
>
> Good catch!
>
> > but other than that
> > _clip_and_composite_source() doesn't look particularly slow to me.
> > It's a straight-forward two-pass rendering operation where
> > both passes can be hardware accelerated and are reasonably
> > MMX accelerated in pixman.
>
> Actually it is pretty slow. The visual results of SOURCE and OVER are
> exactly the same, yet SOURCE is right now 10 times slower in pixman because
> of the operators we replace it with. It should actually be faster. The
> Quartz backend for example is 40 times faster than pixman. And even just in
> Quartz, OVER is 5 times faster than SOURCE.
Well, in the case where they are exactly the same... when we can prove
the source has no alpha... there's no reason we can't optimize SOURCE to
OVER.
I wouldn't agree that SOURCE "should be faster" ... SOURCE should be
faster only if we don't have to reference destination pixels, but that
isn't the case when we have a mask. The code we are discussing is
specific to the case when there is a mask of some type.
- Owen
More information about the cairo
mailing list