[cairo] 8 bit pseudo color missing.
Owen Taylor
otaylor at redhat.com
Wed Mar 22 12:55:08 PST 2006
On Wed, 2006-03-22 at 10:18 -0800, Carl Worth wrote:
> On Wed, 15 Mar 2006 13:59:42 +0100, "Eric Faurot" wrote:
> > So for the record, could somebody with intimate knowledge of cairo internals
> > explain what code needs to be written, and where to hook it up in the
> > current code? It would help somebody really interrested in fixing
> > that to know, at least, where to begin.
>
> The primary place where things are missing is within the pixman code,
> (that is the directory cairo/pixman/src from a cairo checkout or tar
> file).
>
> The pixman code was derived from the fb code in the X server.
>
> The X server does deal with indexed color operations and so to some
> extent the "necessary code" already exists within the X server. When I
> ported fb over to pixman to make a library usable outside of the X
> server, I simply discarded anything related to indexed color
> operations, since I had no interest in doing the work necessary to
> make it functional.
>
> The discarding may have included #ifdefs to prevent code from being
> compiled, or it may have been simply not copying portions of the code
> needed. I really couldn't say for sure now. But a good place to start
> would be comparing the pixman code to the fb code in the X server.
This approach assumes that you can get the color assignments on the
server to agree with what the pixman code wants. If the server has
RENDER of a reasonably recent vintage, then that is going to be the
case, considering the common heritage. But the server might not
have RENDER at all; it's really a question of why pseudo-color support
is wanted - you can imagine various cases:
- Get Cairo working on 10+ year old hardware that only supports
pseudo-color modes.
- Get Cairo running on newer hardware to remote display to an
old X terminal that only supports pseudo-color modes.
- Get Cairo working on newer hardware that supports decent modes,
but where the work hasn't been done to figure out how to
configure the hardware that way.
The last is actually what was brought up last time Pseudo-color
support was brought up in the context of *BSD, but if someone was
going to spend on this fairly hard problem, it seems to me that
time would be better spent trying to solve a bigger piece of
the problem set ... it makes little sense to program to the
fringe of a fringe.
And that makes me think that a better approach would be to, for
software fallbacks, use an internal TrueColor buffer inside of
Cairo, and only convert to and from indexed color when getting an
image from the display or writing the image back to the display.
Then you basically have only two problems to solve:
- How do you grab an image from the screen and convert it
to RGBA data.
The most basic way to do this is to just do
two roundtrips ... query the colormap, and then fetch
the image data. You can get more sophisticated by only
fetching the colormap periodically or by playing Xlib
programming tricks to combine the two roundtrips into
one.
- How do you convert RGBA data back into screen format.
Vast quantities of time were spent on this problem back
when people still cared about Pseudo-color support, but
there are some pretty simple ways to get really basic
results.
Floyd-Steinberg dithering, though it really doesn't work
well for screen display due to discontinuities at the
edges of dithered regions has the nice property that
it is easy to get going with an arbitrary color map
rather than a color cube. As long as you have *some* way
of finding an color in the color map that approximates
the color of the pixel, then you'll get decent results.
It's probably possible to get something appearing on the screen
in a day or so of work with that approach.
Rather then going into a lot more detail about the above, I'll
just mention a few of the problems that would have to be
addressed in making something that wasn't just a complete toy:
- To get pseudo-color display to be at all usable, you need
to dither. However, dithering has the problem of joins -
you can't just glue two separately dithered areas together
and expect it to look right.
I'd suggest for a first approximation, ignoring this.
To get good dithering results, you need to keep track
of a "dither offset". Now, since this has to be dealt with
at all layers ... from the application to the lowest part
of rendering, it's basically an impossibility to get right
these days, since applications just aren't going to care,
but you could do better-than-nothing at only the
Cairo <=> toolkit layer. (In the GTK+ case
cairo_surface_set_device_offset() is almost what you need.)
Or you could do what Carl was suggesting at the X server
level and render the entire screen in true color and dither
down from there. That's not feasible for all use cases.
- It's pretty much of a disaster if you repeatedly dither
to the display and fetch data back. Both from a performance
point of view and an a results point of view. So there are
a couple of things that help all servers without RENDER
that would help even more here:
- Keep data around for the window client side, and only
write at the end ... this is what the flush() and
mark_dirty() APIs are meant to enable.
- Optimize the case where the contents of the destination
are known ... for example, if we create a new pixmap,
and fill it completely with a solid color, then draw
on top of that, then we shouldn't need to ever read
data back from the server.
Finally, it's worth making clear that there's no way things are
going to work as well in pseudo-color modes as they did in 1996.
Getting Pseudo-color working was a delicate balancing job
which required cooperation between all the applications, code
at all levels, and even cooperation from the people doing
the graphic art. That cooperation is no longer there, and people
simply aren't willing to make the necessary compromises.
So, really, hoping for more than "something vaguely recognizable
appears on the screen slowly" may be futile.
Regards,
Owen
More information about the cairo
mailing list