Tuesday, 2. December 2008, 06:34:41
With everyone having an LCD monitor these days,
subpixel rendering is becoming a must. There are patents on this by both Microsoft and Apple, but I'm unsure if they would hold up since subpixel rendering is a technique that is over 25 year old when patents weren't handed out to anyone who wanted one.
Subpixel rendering on LCD screens is the idea of taking advantage of the fact that there are essentially three RGB subpixels for each full pixel. By only activating one or two of the subpixels, you can achieve three times the horizontal resolution and get better font rendering.
Problem. By only activating one color, you will get color ringing around your text. And I don't care what anyone says, subpixel rendering does have color ringing no matter what. For most cases though, it's not TOO bothersome. The ringing usually happens when there's a color imbalance.
Below are two lines. The first line represent three full pixels (or three RGB tuples).
The second line is something that could happen when rendering text where X's are black subpixels. Those X's would be turned off.
RGBRGBRGB
RGXXXXXGB
Notice how the green color is on BOTH sides of the X's? That alone will produce color ringing. More than that, there is a color imbalance. There are two blues and two reds that are shut off, but only one green that is shut off. So the green stands out even more.
Green has another issue. It's what contributes the most to luminance. Blue contributes very little. So when doing subpixel rendering, you will almost never see green ringing, but rather blue and red because you have more freedom with those.
How are these rendered? Well, you need a text rendering engine that is capable of subpixel rendering. Cleartype and Freetype are both capable. Freetype will render an image three times as wide where each item in each triplet is the intensity of each RGB value for that pixel. This is as if we were rendering white on black.
Essentially, the task of subpixel rendering involves alpha blending on each of the RGB values. There is an independent alpha (or intensity) for each subpixel. The algorithm when drawing back to front is relatively easy. If you have a color C (which also include it's own alpha), the equation is this.
AR,AG,AB are the intensities gotten from the subpixel rendering engine.
A,R,G,B are from the text color C.
BR,BG,BB are the old background pixels.
DR,DG,DB are the new background pixels.
DR = A*AR*R + (1-(A*AR))*BR
DG = A*AG*G + (1-(A*AG))*BG
DB = A*AB*B + (1-(A*AB))*BB
So it's no big deal to render this back to front. Here's where I ran into a problem. Unless I provide a background color or a background graphic, I cannot render text in the opposite manner of front to back. Front to back is a popular rendering method because you never draw the same pixel more times than necessary (and opaque pixels never get drawn again). The alpha channel is used as a Z-buffer though you can use a real Z-buffer for more complicated drawing.
The issue is that front to back can't work with subpixel rendering because you need to compute an alpha value for the destination image to be used for future computations. Subpixel rendering requires THREE alpha values from the font rendering engine. You can't fit three alpha values into one.
IOW, when rendering back to front, you don't need to retain any alpha values because the destination image is always 100% opaque. It's always the applied images drawn on top that have translucent parts, if any. However, when drawing front to back, you need to retain the alpha value of each pixel so that you know how much of the underlying images will show through. With subpixel rendering, you would need THREE alpha values for each subpixel instead of the usual one alpha value.
The only way to make this work is to either use a background (opaque color or graphic) when submitting text rendering, or to somehow remember where the fonts are to be drawn (including the alpha values of the area at that time) and afterwards draw the text back to front where they go. I think this would require a lot of work and a significant amount of caching data.
I think I will be using opaque background colors and images for now when doing text rendering. Transparent text is still available, but does not use subpixel rendering. It uses standard full pixel antialiasing techniques and look fine at larger font sizes. So none of this will be a big issue right yet because I normally already know what I'm going do draw behind the text anyhow and have very few floating transparent labels. The one I do have is for FPS and is rather large. It does not need subpixel rendering and won't be there in the final product anyhow.
If someone has a good idea on how subpixel rendering could be done front to back, I'm all ears. I don't think it's possible without three alpha channels. This is why I wish pixel shaders had direct access to the Z-buffer, stencil buffer and destination color buffer. I could use one of those buffers for the alpha channels and no slowdown would occur. But until the destination buffer can also be used as a source, I'll have to find other ways of doing things.