This looks extremely promising; https://bugzilla-attachments-216655.netbeans.org/bugzilla/attachment.cgi?id=153888
I'd say don't let perfect be the enemy of the good, please get this out into a jdk9 release and let the community provide more feedback. On 22 May 2015 at 00:23, Andrew Brygin <andrew.bry...@oracle.com> wrote: > 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 >>>>>>>>> >>>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > -- -Tor