Fwd: [cairo] Re: NEW: cairo rendering in outline mode
Here's a message from a cairo developer - not sure if it reached our list, so I'm forwarding it. It confirms that my initial description was indeed incorrect: Inkscape uses fixed order, while Cairo's order depends on platform. Sorry for the confusion (though it amounts to the same thing from compatibility viewpoint).
---------- Forwarded message ---------- From: Jeff Muizelaar <jeff@...1669...> Date: Feb 25, 2007 5:15 PM Subject: Re: [cairo] Re: [Inkscape-devel] NEW: cairo rendering in outline mode To: bulia byak <buliabyak@...400...> Cc: jiho <jo.irisson@...400...>, cairo@...278..., inkscape List Devel inkscape-devel@lists.sourceforge.net
On Sun, Feb 25, 2007 at 11:10:16AM -0500, bulia byak wrote:
Last night, with the help of Carl Worth, the issue of cairo/inkscape not working on mac was more or less clarified. Here's how I understand it.
When drawing into a memory buffer, cairo uses a fixed byte order of the R, G, B, A bytes regardless of the platform.
This is incorrect. Cairo's byte order depends on the platform. See, for example, pixman/src/fbpict.c:fbOver():
static CARD32 fbOver (CARD32 x, CARD32 y) { CARD16 a = ~x >> 24; CARD16 t; CARD32 m,n,o,p;
m = FbOverU(x,y,0,a,t); n = FbOverU(x,y,8,a,t); o = FbOverU(x,y,16,a,t); p = FbOverU(x,y,24,a,t); return m|n|o|p; }
As is shown, the alpha component is always in the most significant byte. So byte 0 on big endian and byte 3 on little endian.
However, Inkscape's code assumes a fixed byte order (see below). i.e R is byte 0, G is byte 1 etc.
void nr_R8G8B8A8_N_EMPTY_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) { unsigned int r, g, b, a; unsigned int x, y;
r = NR_RGBA32_R (rgba); g = NR_RGBA32_G (rgba); b = NR_RGBA32_B (rgba); a = NR_RGBA32_A (rgba);
for (y = h; y > 0; y--) { if (a == 0) { memset(px, 0, w*4); } else { unsigned char *d = px; const unsigned char *m = mpx; for (x = w; x > 0; x--) { d[0] = r; d[1] = g; d[2] = b; d[3] = NR_PREMUL_111 (m[0], a); d += 4; m += 1; } } px += rs; mpx += mrs; } }
Inkscape and GDK (which is used by Inkscape for drawing to screen), however, both use system-dependent byte order, i.e. the order of R, G, B, A is determined by the hardware and is different on PC and Mac platforms.
And it so happens that the fixed order of cairo coincides with the hardware order on PC but not on Mac. Hence, painting by cairo directly into Inkscape/GDK buffers worked on PC but on Mac, all colors are wrong and (in case of outline) black color gets zero opacity, i.e. becomes invisible.
Essentially, this means that Inkscape and cairo are not compatible as is, and that a gradual switching of parts of our display engine to cairo is not possible. (Unless we ditch Macs, of course.)
Even if we switch our screen output from using GDK to cairo (which is relatively easy), this won't help - it will just break rendering on PCs too. Inkscape has a lot (and I do mean A LOT) of code that assumes system-dependent byte order. Composers, decomposers, premultipliers, unpremultipliers, blitters and blotters of all sizes and colors permeate the codebase. Most of them come all the way from Sodipodi.
Fortunately, cairo has a lot of equivalent code that matches cairo's byte order. It also looks like alot of inkscape's compositing code, like cairo's, isn't particularily fast either.
Now, of course, it's possible to create "adapters" for cairo bits. That is, every time we use cairo, instead of drawing directly into Inkscape buffer, we can draw into a temporary buffer instead, rearrange the bytes in that buffer, and then compose that into the main buffer. But that is certain to more than negate the feeble speed gains we're seeing from cairo's image backend rendering.
Or, we can attempt a much more drastic rearchitecturing, by changing our functions so they pass around cairo contexts instead of Inkscape buffers. With this approach, byte reordering will be needed less frequently, and eventually eliminated completely. But this is not only much more work, it will also mean a lot more bugs and regressions and quite some time before Inkscape is usable again.
So, it looks like due to this stupid byte-order issue, cairo for us is practically an all-or-nothing proposition - and much more hassle than I expected. I'm not saying it's impossible but it is quite a major project that cannot be done gradually.
Unless, of course, cairo gets so in love with Inkscape as to provide us with a new image surface with system-dependent byte order...
This is painful as well. All of cairo's software compositing routines use the cairo byte order, and likewise X assumes this byte order as well.
-Jeff
On Sun, Feb 25, 2007 at 07:01:50PM -0400, bulia byak wrote:
Here's a message from a cairo developer - not sure if it reached our list, so I'm forwarding it. It confirms that my initial description was indeed incorrect: Inkscape uses fixed order, while Cairo's order depends on platform. Sorry for the confusion (though it amounts to the same thing from compatibility viewpoint). However, Inkscape's code assumes a fixed byte order (see below). i.e R is byte 0, G is byte 1 etc.
r = NR_RGBA32_R (rgba); g = NR_RGBA32_G (rgba); b = NR_RGBA32_B (rgba); a = NR_RGBA32_A (rgba);
These macros along with a lot of others that appear to do similar rgba operations are in nr-pixops.h. Perhaps a starting point would be to put #ifdefs around them and provide cairo-compatible versions of each, if some define is specified.
for (y = h; y > 0; y--) { if (a == 0) { memset(px, 0, w*4); } else { unsigned char *d = px; const unsigned char *m = mpx; for (x = w; x > 0; x--) { d[0] = r; d[1] = g; d[2] = b; d[3] = NR_PREMUL_111 (m[0], a);
Next would be to find all the places where byte-order dependent operations are being done, and add new macros in nr-pixops.h or some other central place for those things that allow them to be ifdef'd as well.
Bryce
participants (2)
-
Bryce Harrington
-
bulia byak