[OpenJDK 2D-Dev] [9] Review request for 8023794: [macosx] LCD Rendering hints seems not working without FRACTIONALMETRICS=ON

Andrew Brygin andrew.brygin at oracle.com
Thu May 21 14:23:09 UTC 2015


Hello Phil,

  I have changed the default reverse gamma to 180:

  http://cr.openjdk.java.net/~bae/8023794/9/webrev.10/

  I also did some experiments with the lcd contrast, and found that
  value 160 decreases the discrepancy a bit: 21 instead of 29 with
  the default lcd contrast value (140).
  However, there still is the discrepancy, and at the moment I do not
  see how we can avoid it completely with our rendering model.
  It looks like that  there is something more sophisticated than
  just gamma correction, and we are unable to derive 'color independent'
  glyphs from black-on-white glyphs provided by the native system.

  I have also played with changing display profiles but it seems to
  have no detectable effect.

  Thanks,
Andrew

On 5/18/2015 11:19 PM, Phil Race wrote:
> Hi,
>
> So 1.79 is essentially 1.8 which is what Mac historically used as 
> gamma. So I'd pick 180 instead of 179
> Since that value minimises the discrepancy it's looking positive but 
> there's still a discrepancy.
> Before we 'live with it',  I'd be interested to know what happens if 
> you set your display's profile to a generic RGB one.
>
> How do the glyph shapes (if you try your best to ignore the colour) 
> match what other apps produce ?
>
> -phil.
>
>
> On 04/30/2015 06:21 AM, Andrew Brygin wrote:
>> Hello Phil,
>>
>>  please take a look to updated version of the fix:
>>
>> http://cr.openjdk.java.net/~bae/8023794/9/webrev.09/
>>
>> The main difference is in glyph generation. I have implemented 
>> 'reverse gamma correction'
>>  approach instead of 'glyph blending'. By default we use gamma value 
>> which provides minimum
>>  of discrepancy with gyph images produced by Apple's jdk. However, it 
>> can be adjusted via
>>  environment variable J2D_LCD_REVERSE_GAMMA (CGGlyphImages.m, lines 
>> 198 - 220).
>>
>>  Following chart illustrates dependency between the 'reverse gamma' 
>> and a difference
>>  in pixel values comparing to jdk6 from Apple:
>> http://cr.openjdk.java.net/~bae/8023794/best_reverse_gamma.png
>>
>>  Following set of images has been used for the comparison:
>> http://cr.openjdk.java.net/~bae/8023794/images/
>>  An index of image corresponds to the value of reverse gamma used for 
>> image
>>  generation.
>>
>> Beside this, following minor changes were done:
>>  * RenderingHints.KEY_ANTIALIASING was removed form fontHints,
>>      because it has no direct relation to text rendering, and does 
>> not have
>>      any effect at the moment.
>>  * A comment regarding unevaluated rendering hints was added.
>>
>>  Please take a look.
>>
>> Thanks,
>> Andrew
>>
>> On 4/24/2015 7:33 PM, Andrew Brygin wrote:
>>> Hello Phil,
>>>
>>>  please see my comments inline.
>>> On 4/23/2015 11:15 PM, Phil Race wrote:
>>>>
>>>>  373         fontHints.put(RenderingHints.KEY_ANTIALIASING, 
>>>> RenderingHints.VALUE_ANTIALIAS_ON);
>>>>
>>>> Why do we need this ? Historically in the (non-OSX) code this would 
>>>> slow things down by making
>>>> text rendering go via ductus rendering.
>>>> If this really is a 'fontsHint' map,  it seems it should not be here.
>>>
>>> I agree that this particular hint has no direct relation to the font 
>>> hints,
>>> and probably should not be here. I guess that KEY_ANTALIASING was put
>>> here in order to force text antialiasing on when default text 
>>> antailiasing is evaluating:
>>>
>>> http://hg.openjdk.java.net/jdk9/client/jdk/file/0e483e64c1e4/src/java.desktop/share/classes/sun/java2d/SurfaceData.java#l741 
>>>
>>>
>>> I do not think that it has any effect now, because we set text 
>>> antialiasing hint explicitly.
>>> I will check whether it can be safely removed.
>>>
>>>>  410 sg2d.surfaceData.getTransparency() == Transparency.OPAQUE &&
>>>>
>>>> I thought you were removing this condition ?
>>> I have rolled this change back, because at the moment lcd shader
>>> produces ugly results in the case of translucent destination.
>>> There is a separate bug regarding the translucent destination support:
>>>
>>> https://bugs.openjdk.java.net/browse/JDK-8078516
>>>
>>> I am going to relax this condition when(if) our lcd shader will be 
>>> ready.
>>>
>>> In fact, this problem is not limited by ogl, because d3d and 
>>> software loops
>>> has the same limitation.
>>>
>>>
>>>>
>>>> CGGlyphImages.m
>>>>
>>>>  202 #if __LITTLE_ENDIAN__
>>>>  203     *(dst + 2) = 0xFF - (p >> 24 & 0xFF);
>>>>  204     *(dst + 1) = 0xFF - (p >> 16 & 0xFF);
>>>>  205     *(dst) = 0xFF - (p >> 8 & 0xFF);
>>>>  206 #else
>>>>  207     *(dst) = 0xFF - (p >> 16 & 0xFF);
>>>>  208     *(dst + 1) = 0xFF - (p >> 8 & 0xFF);
>>>>  209     *(dst + 2) = 0xFF - (p & 0xFF);
>>>>  210 #endif
>>>>  211 }
>>>>
>>>> became
>>>>  217 {
>>>>  218     *(dst + 0) = 0xFF - (p >> 16 & 0xFF);  // red
>>>>  219     *(dst + 1) = 0xFF - (p >>  8 & 0xFF);  // green
>>>>  220     *(dst + 2) = 0xFF - (p & 0xFF);        // blue
>>>>  221 }
>>>>
>>>>
>>>> I started by assuming you were removing the BIG_ENDIAN code that
>>>> was probably legacy PPC code but instead I see that the 
>>>> LITTLE_ENDIAN case is removed,
>>>> so I don't understand this.
>>>>
>>>> And further down the file now I see that in 
>>>> ConvertBWPixelToByteGray you did remove the big endian case.
>>>>
>>>
>>> Note that we are
>>> Please note that we force the lcd glyph generation by requesting
>>> host (i.e. LITTLE_ENDIAN) byte order for the canvas bitmap:
>>>
>>>  407     uint32_t bmpInfo = kCGImageAlphaPremultipliedFirst;
>>>  408     if (mode->glyphDescriptor == &rgb) {
>>>  409         bmpInfo |= kCGBitmapByteOrder32Host;
>>>  410     }
>>>
>>> So, before the fix (and for grayscale case now) the buffer has default
>>> BIG_ENDIAN order. I.e. grayscale canvas stores data in following 
>>> format:
>>>
>>> as bytes:  A R G B
>>> as int:   0xBBGGRRAA
>>>
>>> The same byte order was used for the rgb canvas before the fix.
>>> But now the canvas is configured to store data in following format:
>>>
>>> as bytes: B G R A
>>> as int: 0xAARRGGBB
>>>
>>> So, data extraction routines were updated accordingly.
>>>
>>>> 365 case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_GASP:
>>>>  366     case sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_DEFAULT:
>>>>  367     default:
>>>>  368         e = [NSException
>>>>  369 exceptionWithName:@"IllegalArgumentException"
>>>>  370                 reason:@"Invalid hint value"
>>>>  371                 userInfo:nil];
>>>>
>>>>
>>>> I think this means that by the time we get here we should not have 
>>>> DEFAULT or GASP
>>>> but we should have the actual interpretation for this surface, font 
>>>> and point size.
>>>> So this looks correct but maybe you can add a comment on this.
>>>
>>> will do.
>>>
>>>> The heuristic of blending black and white is interesting.
>>>> How did you arrive at this ? It suggests that the glyph bitmap we 
>>>> are caching is
>>>> not 'colour neutral' which is odd. Maybe we are missing code to apply
>>>> the 'reverse gamma correction' ?
>>>
>>> I have played with the idea about 'reverse gamma correction', it 
>>> seemed very attractive to me.
>>> Roughly speaking, gamma > 1 makes black-on-white glyphs a bit 
>>> narrower, and white-no-black
>>> glyphs a bit wider (bolder?), and it is the same effect that we need.
>>> Unfortunately, direct comparison  of black-on-white and 
>>> white-on-black glyphs makes me think
>>> that difference between these glyphs can not be explained only by 
>>> gamma correction.
>>>
>>> Please take a look at this screenshot:
>>> http://cr.openjdk.java.net/~bae/8023794/bw-wb-comparision.png 
>>> <http://cr.openjdk.java.net/%7Ebae/8023794/bw-wb-comparision.png>
>>>
>>> row 1: text is rendered by jdk6 as-is.
>>> row 2: simulates our pipeline where black-on-white glyphs are used 
>>> (max error on white-on-black)
>>> row 3: simulates our pipeline where white-on-black glyphs are used 
>>> (max error on black-on-white)
>>> row 4: blended glyphs are used.
>>>
>>> The basic idea of blending is to minimize max error (difference) 
>>> between produced glyph image
>>> and original color-aware glyphs.
>>>
>>> If better results can be achieved with 'reverse gamma correction', 
>>> we can revise this code later.
>>>
>>>> And can (should) any of these changes also be applied to D3D ?
>>>
>>> 1. We can check how gamma correction is done in d3d. If a lookup is 
>>> also used there,
>>>     we can assess how rough the interpolation is.
>>>
>>> 2. translucent destination support (as a part of JDK-8078516)?
>>>
>>> Thanks,
>>> Andrew
>>>
>>>>
>>>> -phil.
>>>>
>>>> On 03/27/2015 07:50 AM, Andrew Brygin wrote:
>>>>> There is a minor update in the fix: it does not worth to blend 
>>>>> black-on-white
>>>>> and white-on-black glyphs for the case of AA glyphs, because it 
>>>>> makes no difference.
>>>>> CGGlyphImages.m, lines 294 - 325, 755 - 763, and 787 - 794:
>>>>>
>>>>> http://cr.openjdk.java.net/~bae/8023794/9/webrev.08
>>>>>
>>>>> I have also modified the AntialiasDemo a bit in order to render the
>>>>> sample text in different colors, and in order to render into a 
>>>>> volatile
>>>>> image as well:
>>>>> http://cr.openjdk.java.net/~bae/8023794/demo/AntialiasDemo.java
>>>>>
>>>>> It could be used to assess the change in glyph generation.
>>>>>
>>>>> Thanks,
>>>>> Andrew
>>>>>
>>>>> On 3/26/2015 3:59 PM, Andrew Brygin wrote:
>>>>>> Hi Chris,
>>>>>>
>>>>>>  thank you for the comments and explanation. I have updated the 
>>>>>> OGLContext_IsLCDShaderSupportAvailable()
>>>>>>  and comments in OGLTextRenderer.c accordingly:
>>>>>>
>>>>>> http://cr.openjdk.java.net/~bae/8023794/9/webrev.07/
>>>>>>
>>>>>>  Good to know that you keep an eye on the OGL pipeline :)
>>>>>>
>>>>>> Thanks,
>>>>>> Andrew
>>>>>>
>>>>>> On 3/25/2015 8:24 PM, Chris Campbell wrote:
>>>>>>> Hi Andrew,
>>>>>>>
>>>>>>> That's a good find re: pow().  In the comment at lines 277-283 I 
>>>>>>> mentioned that there was only a scalar variant of pow().  I 
>>>>>>> wonder if that was a limitation in some early version of GLSL I 
>>>>>>> was using or perhaps some driver bug/restriction.  According to 
>>>>>>> all the docs I can find the vector variants have been there all 
>>>>>>> along:
>>>>>>> https://www.opengl.org/sdk/docs/man4/index.php
>>>>>>>
>>>>>>> So now I'm wondering if the slowness was actually due to me 
>>>>>>> trying 3 scalar pow() calls versus one vector pow() call.
>>>>>>>
>>>>>>> Oh, aha!  I think this explains part of it:
>>>>>>>
>>>>>>>  269  * This is the GLSL fragment shader source code for 
>>>>>>> rendering LCD-optimized
>>>>>>>  270  * text.  Do not be frightened; it is much easier to 
>>>>>>> understand than the
>>>>>>>  271  * equivalent ASM-like fragment program!
>>>>>>>
>>>>>>> Looks like I wrote the original version of this shader using the 
>>>>>>> GL_ARB_fragment_program language, which indeed only had a scalar 
>>>>>>> POW instruction (see section 3.11.5.20):
>>>>>>> https://www.opengl.org/registry/specs/ARB/fragment_program.txt
>>>>>>>
>>>>>>> And then I'm guessing that when I rewrote it in more modern 
>>>>>>> GLSL, I didn't notice that pow() supported vectors.  Sigh. That 
>>>>>>> 3D texture LUT was a lot of work for a whole lot of nothing.
>>>>>>>
>>>>>>> In any case, you might want to rewrite the comment at lines 
>>>>>>> 277-283 to suit the new code.  Same goes for the comment at line 
>>>>>>> 315:
>>>>>>>
>>>>>>>     // gamma adjust the dest color using the invgamma LUT
>>>>>>>
>>>>>>> Also, I noticed that the restrictions in 
>>>>>>> OGLContext_IsLCDShaderSupportAvailable() could be loosened since 
>>>>>>> you only need 2 texture units now. Just in the extremely 
>>>>>>> unlikely case that anyone's running this stuff on ancient 
>>>>>>> hardware :)
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Chris
>>>>>>>
>>>>>>>
>>>>>>> Andrew Brygin wrote:
>>>>>>>> Hello Phil,
>>>>>>>>
>>>>>>>> could you please take a look to updated version of the fix?
>>>>>>>>
>>>>>>>> http://cr.openjdk.java.net/~bae/8023794/9/webrev.06/
>>>>>>>>
>>>>>>>> * OGLTextRenderer.c
>>>>>>>> It was discovered, that in some cases lcd glyphs had visible 'dark
>>>>>>>> border' around.
>>>>>>>> This border appeared due to the gamma correction in lcd shader, 
>>>>>>>> which
>>>>>>>> uses lookup
>>>>>>>> on 3D texture instead of using 'pow' routine. The texture is 
>>>>>>>> populated
>>>>>>>> with significant
>>>>>>>> granularity (16 points per edge), what is a root cause of rough
>>>>>>>> interpolation of color values.
>>>>>>>> Suggested change is to eliminate the interpolation and use 
>>>>>>>> 'pow' routine
>>>>>>>> directly.
>>>>>>>> It gives more accurate color values, and does not introduce 
>>>>>>>> significant
>>>>>>>> performance hit
>>>>>>>> (see benchmark summary below).
>>>>>>>> However, this part of the fix affects not only macosx, but any 
>>>>>>>> platform
>>>>>>>> where OGL text
>>>>>>>> shader can be used, so it probably worth to split into a 
>>>>>>>> separate fix.
>>>>>>>>
>>>>>>>> Summary:
>>>>>>>> lcd-ogl-3Dlookup:
>>>>>>>> Number of tests: 4
>>>>>>>> Overall average: 42.68027553311743
>>>>>>>> Best spread: 3.49% variance
>>>>>>>> Worst spread: 29.59% variance
>>>>>>>> (Basis for results comparison)
>>>>>>>>
>>>>>>>> lcd-ogl-pow:
>>>>>>>> Number of tests: 4
>>>>>>>> Overall average: 42.468941501367084
>>>>>>>> Best spread: 2.51% variance
>>>>>>>> Worst spread: 29.44% variance
>>>>>>>> Comparison to basis:
>>>>>>>> Best result: 103.28% of basis
>>>>>>>> Worst result: 97.36% of basis
>>>>>>>> Number of wins: 1
>>>>>>>> Number of ties: 2
>>>>>>>> Number of losses: 1
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Andrew
>>>>>>>>
>>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>




More information about the 2d-dev mailing list