[OpenJDK 2D-Dev] MaskFill incorrect gamma correction (sRGB != linear RGB)

Jim Graham james.graham at oracle.com
Thu Aug 14 20:09:50 UTC 2014

Hi Laurent,

Java2D has color correction code in it, but it is only really hooked up 
to the specific color correction classes so it pretty much has to be 
manually invoked.  The rendering pipeline usually punts on issues like 
color space other than if you specify an alternate color space for a 
BufferedImage then it may classify the image as "Custom" and use a lot 
of really slow custom rendering pipelines (as in, "I have no idea how 
colors are stored there so let's make method calls per pixel to read and 
write them").

By default it assumes that sRGB is a close enough approximation for any 
screen output device and just does pretty straightforward math on the 
pixel values and pretends that it is doing it all "in sRGB space".  In 
reality, it is doing it all in "just computing with the color 
components" space and assuming that since the output is a screen then it 
is essentially "sort of playing in sRGB space".  The assumption works 
fine for GUI and casual rendering, but more deliberate treatment of 
color spaces would really be needed for things like pre-press.

In particular, it does no gamma correction except in the LCD text loops 
- those are so finicky when it comes to getting the AA just right in 
terms of quality that they really required us to do gamma corrected 
blending or the results just wouldn't be readable.  But, all other AA 
rendering (and alpha rendering) is done just linearly in the space of 
the component values.

Note that to do the gamma correction for LCD text in the hw accelerated 
pipelines we have to read back the screen so that we can convert them 
into gamma space and back again.  This greatly increases the cost of the 
rendering and if we did the same thing for regular shape rendering then 
there would be a significant performance hit.  I believe that future 
versions of D3D and OpenGL will eventually support gamma corrected 
blending natively, but for now the gamma decorrection on the destination 
has to be implemented with manual computations in a shader.  If you 
combine that with the fact that shaders cannot access the output pixel 
then there is no way to do that correction without reading back from the 
screen and providing those pixel values as a secondary input to the 
shader.  Note that you can't simply bind the output surface as an input 
texture because neither API allows a texture to be bound as both the 
input and output of the same operation - so a readback has to be done. 

Another possibility is to store all pixel values internally in a linear 
sRGB space and to de/re-gamma them as we copy them to the screen, then 
we could avoid the readback in most cases at the cost of a single gamma 
conversion on the final blit, but that would take a serious overhaul to 
the rendering pipelines to accomplish and we haven't even prototyped 
something like that.  Rendering directly to the screen via 
"Window.getGraphics()", though, would need to do the readback for every 
render operation...


On 8/14/14 3:00 AM, Laurent Bourgès wrote:
> Hi,
> Here are questions about the java2d pipeline to understand how colors
> are handled as pixel values (conversions):
> - BufferedImage use by default the sRGB colorspace (non linear) so its
> raster data (RGBA) are encoded as int values (sRGB).
> What parts of the java2d pipeline handle color blending in linear RGB
> (quality issue) ?
> AlphaComposite impl (ogl, xr) .... like the SrcOver operator.
> Blit ?
> The Javadoc explains conversions between premultiplied alpha images...
> but nothing about the colorspace of pixels.
> Is it supposed to be always sRGB = the java native color space ?
> So the complete pipeline should deal with gamma correction at every
> color blending stage...
> - if I create a BufferedImage with the CS_LINEAR_RGB colorspace (RGBA
> values), I expected the image to have better quality but the final PNG
> image remains the same.
> Conversion into sRGB happened at some stage or the PNG encoder is buggy ?
> - Is it possible to implement a custom MaskBlit / MaskFill in java ? Or
> I must fix the C implementations dealing with all possible pixel formats
> (rgb, rgba, rgb555 ....) in every pipeline (software, opengl, xrender,
> direct3d...)
> - how could I use an alternative colorspace (cie-lch for example) with
> the current pipelines to make color blending in this perfect colorspace
> and convert the final image back to sRGB ?
> Thanks for your feedback,
> Laurent

More information about the 2d-dev mailing list