Bug 8550

Summary: bug in gcc 4.0.1 causes big alpha channel problems.
Product: cairo Reporter: nickg <bulk>
Component: generalAssignee: Carl Worth <cworth>
Status: RESOLVED FIXED QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: blocker    
Priority: high    
Version: 1.2.4   
Hardware: PowerPC   
OS: Mac OS X (All)   
Whiteboard:
i915 platform: i915 features:
Bug Depends on: 7497    
Bug Blocks:    

Description nickg 2006-10-07 18:57:00 UTC
Hi there,

you'll love this one.  Here's my compiler

nickgmini:~/unix/cairo-1.2.4 nickg$ gcc -v
Using built-in specs.
Target: i686-apple-darwin8
Configured with: /private/var/tmp/gcc/gcc-5363.obj~28/src/configure --disable-checking -enable-
werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-
transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-
slibdir=/usr/lib --build=powerpc-apple-darwin8 --with-arch=nocona --with-tune=generic --
program-prefix= --host=i686-apple-darwin8 --target=i686-apple-darwin8
Thread model: posix
gcc version 4.0.1 (Apple Computer, Inc. build 5363)

I can hear the groans already.  yes, it's mac os x.

This compiler, at least with intel processors has a major bug which makes cairo useless.

When compiling with -O3, the compiler miscasts the "alpha_short" value in _cario_color_t to a SIGNED 
short not a UNSIGNED short value causing color mayhem.

When using the set_color_rgb function, the alpha channel is set to 0.5 not 1.0 !!!

Here's proof:

I added a printf statement at the end of static void 
_cairo_color_compute_shorts (cairo_color_t *color) {
...
    color->alpha_short = (unsigned)(color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON);
    printf("compute shorts: alpha is %f %d %f\n", color->alpha, color->alpha_short,
           color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON);
}



--> compute shorts: alpha is 1.000000 32767 65535.999990

As you see the short value SHOULD be 65535.

This took about 6 hours to figure out.

The fix is to add a cast to a unsigned int.  casting to unsigned short does not work!

around line 115 in cairo-color.c

    /**                                                                                                                                 
     * The cast to (unsigned) is technically not needed, BUT the gcc                                                                    
     * 4.0.1 compiler (used by Mac OS X 10.4.X) has a bug.  Under -O3                                                                   
     * the double value gets converted to a SIGNED short (max 32673)                                                                    
     * instead of a unsigned short.  Explcity casting to (unsigned                                                                      
     * short) does not work.  First, casting to a normal unsigned int                                                                   
     * appears to work (and then automatically cast to unsigned short).                                                                 
     * This bug is not triggered under -O2.                                                                                             
     */
    color->alpha_short = (unsigned)(color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON);


Only the alpha channel is effected.  The other channels are ok.
This only occurs when compiling at -O3, -O2 is fine
This only occurs when using the set_rgb, not set_rgba functions
It does not matter if the image soruce is RGB24 or ARGB32

I have not checked to see if the same problem occurs with other cpus / os

Given that this is the default compiler for Mac OS ,  this is bummer.  If not a patch we should add a note 
in README not to use -O3 for this compiler.

let me know if you need any more details,

thanks,

--nickg


stupid sample program:

#include <cairo.h>
#include <cairo-pdf.h>
#define WIDTH 400
#define HEIGHT 400

#define COMPOSITE_OP CAIRO_OPERATOR_OVER

void paintit(cairo_surface_t* cs)
{
    cairo_t* ctx = cairo_create (cs);
    cairo_set_operator(ctx, COMPOSITE_OP);
    cairo_set_source_rgb(ctx, 0.0, 1.0, 1.0);
    cairo_paint(ctx);
    cairo_set_source_rgb(ctx, 1.0, 0.0, 0.0);
    cairo_set_line_width(ctx, 15);
    cairo_move_to(ctx,200,100);
    cairo_line_to(ctx,300, 300);
    cairo_rel_line_to(ctx,-200,0);
    cairo_close_path(ctx);
    cairo_stroke(ctx);
    cairo_rectangle(ctx, 0, 0, 250, 250);
    cairo_set_source_rgb(ctx, 0, 0, 0);
    cairo_fill(ctx);
    cairo_show_page(ctx);
    cairo_destroy (ctx);
}
int main() {
    cairo_surface_t *cs;                                           
    cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
    paintit(cs);
    cairo_surface_write_to_png (cs, "triangle_argb32.png");
    cairo_surface_destroy(cs);
    return 0;
}
Comment 1 nickg 2006-10-07 19:00:04 UTC
Ughh, I goofed.. it should be

"""
I added a printf statement at the end of static void 
_cairo_color_compute_shorts (cairo_color_t *color) {
...
    color->alpha_short =color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
    printf("compute shorts: alpha is %f %d %f\n", color->alpha, color->alpha_short,
           color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON);
}
"""

This correctly shows the bug... the version before has my patch in it.

enjoy
--nickg



Comment 2 Behdad Esfahbod 2006-10-08 12:38:51 UTC
We are going to rewrite that function in a more robust way.  Marking urgent to
make sure it doesn't slip.
Comment 3 Behdad Esfahbod 2006-10-16 09:42:35 UTC
Can you check the latest git trunk to see if this is fixed now?
It should be.
Comment 4 nickg 2006-10-16 18:59:30 UTC
Hi there... wow this was a nightmare to test.. I had to install new versions of git/autoconf/libtool/
automake... and the autoreconf'ed configure script has bugs in pkg-config part so I had to hack that too... 
but... the result is....

WORKS!  -O3 produces the correct output.

thanks everyone.

--nickg
Comment 5 nickg 2006-10-16 19:01:25 UTC
Hi there... wow this was a nightmare to test.. I had to install new versions of git/autoconf/libtool/
automake... and the autoreconf'ed configure script has bugs in pkg-config part so I had to hack that too... 
but... the result is....

WORKS!  -O3 produces the correct output.

thanks everyone.

--nickg
Comment 6 Behdad Esfahbod 2006-10-16 20:29:46 UTC
(In reply to comment #5)
> Hi there... wow this was a nightmare to test.. I had to install new versions
of git/autoconf/libtool/
> automake... and the autoreconf'ed configure script has bugs in pkg-config part
so I had to hack that too... 

What was the pkg-config problem?  We want to fix that too.
Comment 7 nickg 2006-10-17 07:46:32 UTC
I filled my pkg-config/autotools mayhem in 8686...  Let me know if you need more details.
--nickg

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.