[cairo] Cairo+Direct3D interaction bug and fix (x86 FPU precision)
pauli at lacquer.fi
Mon Oct 16 06:08:23 PDT 2006
I'm making a Windows GTK+ app that also uses Direct3D for some separate
rendering within the same process. Unfortunately simply creating a Direct3D
device breaks Cairo's rendering: most drawing operations will produce no output.
After a day of pulling my hair out, I finally discovered the fix. The root of
the problem is that Direct3D switches the FPU to single-precision mode, which
causes _cairo_color_compute_shorts() in cairo-color.c to produce incorrect
values. More specifically, the code assumes that 1.0 *
CAIRO_COLOR_ONE_MINUS_EPSILON will produce 65535.0... But when the FPU is in
single-precision mode, that computes to 65536.0 instead, so the uint16 value
overflows to 0.
Now that I'm aware of Direct3D's evil FPU manipulation, I found a special flag
that can be used to disable this behavior in D3D (it's rather nuts that they
silently mess with the FPU by default).
Although in this case it was all Microsoft's fault, it might still be useful if
Cairo took into account the possibility that the x87 FPU is in single-precision
mode. Even just doing a simple test and printing out a big warning in case the
expected epsilon rounds to zero might spare a lot of time for someone who's
trying to use Direct3D. And there may also be other platforms out there where
doubles are really floats, so Cairo would be better prepared for that.
More information about the cairo