[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.
(Grrr)
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...
...jim
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