From james.graham at oracle.com Tue Dec 1 23:04:10 2015 From: james.graham at oracle.com (Jim Graham) Date: Tue, 1 Dec 2015 15:04:10 -0800 Subject: [OpenJDK Rasterizer] Fix Overflow in Marlin ArrayCache In-Reply-To: References: Message-ID: <565E276A.6080704@oracle.com> Hi Laurent, I submitted the following bug: https://bugs.openjdk.java.net/browse/JDK-8144445 The change looks fine. Are the long modifiers (12L, 1L, etc) really needed on the shift parameters given that the first operand (needSize) is already a long? 202 size = ((needSize >> 12L) + 1L) << 12L; ...jim On 11/27/15 3:42 AM, Laurent Bourg?s wrote: > Hi, > > Here is a new webrev that fix the Renderer usage of getNewLargeSize() as > the overflow check fails due to integer maths: > http://cr.openjdk.java.net/~lbourges/marlin/marlin-s6.1/ > > Patched line: > > final long edgeNewSize = ArrayCache.getNewLargeSize(_edges.length, > - edgePtr + _SIZEOF_EDGE_BYTES); > + ((long)edgePtr) + _SIZEOF_EDGE_BYTES); > > > The CrashTest passes again after the fix (automated tests are very cool) ! > > Laurent > > 2015-11-27 12:18 GMT+01:00 Laurent Bourg?s >: > > Hi Jim, > > Here is a simple fix on potential overflow in > ArrayCache.getNewLargeSize() discussed during Marlin integration: > http://cr.openjdk.java.net/~lbourges/marlin/marlin-s6.0/ > > I added the ArrayCacheSizeTest class which now passes in jtreg. > > Could you create a bug, I am not sure what I should fill in the form ? > > Laurent > > > > > -- > -- > Laurent Bourg?s From bourges.laurent at gmail.com Thu Dec 3 20:49:33 2015 From: bourges.laurent at gmail.com (=?UTF-8?Q?Laurent_Bourg=C3=A8s?=) Date: Thu, 3 Dec 2015 21:49:33 +0100 Subject: [OpenJDK Rasterizer] Marlin artefact issue (Pisces too ?) Message-ID: Jim, I should create a new bug concerning both Marlin & Pisces but I prefer discussing the problem first. A Marlin user reported me an issue with (text outline) rendering artefacts (due to partial cleanup in arrays). Using Marlin with -Dsun.java2d.renderer.doChecks=true (logs re-enabled), we detected that edgeBucketCounts arrays were not properly zero-filled due to NaN coordinates ie array[0] > 0 ! As it only happens with very large coordinates and round joins, we finally got a reproducer test class. However, we tracked the problem down into the Stroker.drawBezApproxForArc() method (from Pisces): cv = NaN. I am not very good at curve maths but I figured out that cosext2 means cos(ext)^2 as there is below sqrt(0.5 +/- cosext2) ! Of course, the problem is sqrt(negative) gives NaN ! Moreover, it only happens with very large out-of-clip coordinates (2M), see the test class ! It probably means that float values have not enough precision in previous math operations and it finally overflows 0.5 ! Is it correct to clamp cosext2 in [-0.5, 0.5] range as I propose ? // the input arc defined by omx,omy and mx,my must span <= 90 degrees. private void drawBezApproxForArc(final float cx, final float cy, final float omx, final float omy, final float mx, final float my, boolean rev) { float cosext2 = (omx * mx + omy * my) / (2f * lineWidth2 * lineWidth2); // PROPOSED FIX TO BE CONFIRMED: // clamp value within [-0.5, 0.5] range: if (cosext2 < -0.5f) { cosext2 = -0.5f; } else if (cosext2 > 0.5f) { cosext2 = 0.5f; } // cv is the length of P1-P0 and P2-P3 divided by the radius of the arc // (so, cv assumes the arc has radius 1). P0, P1, P2, P3 are the points that // define the bezier curve we're computing. // It is computed using the constraints that P1-P0 and P3-P2 are parallel // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|. float cv = (float) ((4.0 / 3.0) * sqrt(0.5 - cosext2) / (1.0 + sqrt(cosext2 + 0.5))); If you have any explanations, please tell me ! PS: Anyway NaN handling must be properly tested and filtered in Marlin's pipeline (like DuctusRenderingEngine does) ... but here it concerns intermediate points (not inputs). Test code: /* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; /** * @test * @summary Check the Stroker.drawBezApproxForArc() bug: * abs(cosext2) > 0.5 generates curves with NaN coordinates * @run main TextClipErrorTest */ public class TextClipErrorTest { public static void main(String[] args) { BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = image.createGraphics(); g2d.setColor(Color.red); try { g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Font font = g2d.getFont(); FontRenderContext frc = new FontRenderContext( new AffineTransform(), true, true); GlyphVector gv1 = font.createGlyphVector(frc, "\u00d6"); g2d.setStroke(new BasicStroke(4.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); AffineTransform at1 = AffineTransform.getTranslateInstance( -2091202.554154681, 5548.601436981691); g2d.draw(at1.createTransformedShape(gv1.getOutline())); GlyphVector gv2 = font.createGlyphVector(frc, "Test 2"); AffineTransform at2 = AffineTransform.getTranslateInstance( // -218.1810476789251, 85.12774919422463); 10, 50); g2d.draw(at2.createTransformedShape(gv2.getOutline())); final File file = new File("TextClipErrorTest.png"); System.out.println("Writing file: " + file.getAbsolutePath()); ImageIO.write(image, "PNG", file); } catch (IOException ex) { ex.printStackTrace(); } finally { g2d.dispose(); } } } Cheers, Laurent -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.graham at oracle.com Fri Dec 4 01:06:15 2015 From: james.graham at oracle.com (Jim Graham) Date: Thu, 3 Dec 2015 17:06:15 -0800 Subject: [OpenJDK Rasterizer] Marlin artefact issue (Pisces too ?) In-Reply-To: References: Message-ID: <5660E707.1010109@oracle.com> It's been a while since I went through that code, but the *mxy numbers tend to be the perpendicular vectors at the vertices (multiplied by the line width). omx*mx + omy*my looks like the dot product of two vectors which produces "len(v1) * len(v2) * cos(angle v1,v2)", so dividing it by lineWidth2 twice reduces it to the cosine of the two vectors and the extra factor of 2 in the denominator means it is actually half of the cosine of the angles at the start and end of the arc - i.e. cos(ext)/2. It should be in the indicated range, but rounding error could mean it may be occasionally outside of that range. I can see where very long line widths might cause problems. Since cv is a function only of cosext2 it might be better to simply assign the value of cv directly, as in: if (cosext2 <= -0.5f) { cv = the answer for -0.5 // 4/3? } else if (cosext >= 0.5f) { cv = the answer for +0.5 // 0.0? } else { cv = current formula } Note that a cv value of 0.0 would insert an empty cubic so we could probably just return right there instead of setting cv to 0.0 and computing a bunch of useless values. Also, the function should only ever be called with a maximum of a right angle so we should never see negative numbers in any case - are you seeing -0.5 values or just +0.5 values? The fix could be as simple as "if (cosext2 >= 0.5) return;" ...jim On 12/3/15 12:49 PM, Laurent Bourg?s wrote: > Jim, > > I should create a new bug concerning both Marlin & Pisces but I prefer > discussing the problem first. > > A Marlin user reported me an issue with (text outline) rendering > artefacts (due to partial cleanup in arrays). > Using Marlin with -Dsun.java2d.renderer.doChecks=true (logs re-enabled), > we detected that edgeBucketCounts arrays were not properly zero-filled > due to NaN coordinates ie array[0] > 0 ! > > As it only happens with very large coordinates and round joins, we > finally got a reproducer test class. > > However, we tracked the problem down into the > Stroker.drawBezApproxForArc() method (from Pisces): > cv = NaN. > > I am not very good at curve maths but I figured out that cosext2 means > cos(ext)^2 as there is below sqrt(0.5 +/- cosext2) ! > > Of course, the problem is sqrt(negative) gives NaN ! > > Moreover, it only happens with very large out-of-clip coordinates (2M), > see the test class ! > It probably means that float values have not enough precision in > previous math operations and it finally overflows 0.5 ! > > Is it correct to clamp cosext2 in [-0.5, 0.5] range as I propose ? > > // the input arc defined by omx,omy and mx,my must span <= 90 degrees. > private void drawBezApproxForArc(final float cx, final float cy, > final float omx, final float omy, > final float mx, final float my, > boolean rev) > { > float cosext2 = (omx * mx + omy * my) / (2f * lineWidth2 * > lineWidth2); > > // PROPOSED FIX TO BE CONFIRMED: > // clamp value within [-0.5, 0.5] range: > if (cosext2 < -0.5f) { > cosext2 = -0.5f; > } else if (cosext2 > 0.5f) { > cosext2 = 0.5f; > } > > // cv is the length of P1-P0 and P2-P3 divided by the radius of > the arc > // (so, cv assumes the arc has radius 1). P0, P1, P2, P3 are > the points that > // define the bezier curve we're computing. > // It is computed using the constraints that P1-P0 and P3-P2 > are parallel > // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|. > float cv = (float) ((4.0 / 3.0) * sqrt(0.5 - cosext2) / > (1.0 + sqrt(cosext2 + 0.5))); > > If you have any explanations, please tell me ! > > PS: Anyway NaN handling must be properly tested and filtered in Marlin's > pipeline (like DuctusRenderingEngine does) ... > but here it concerns intermediate points (not inputs). > > Test code: > /* > * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. > * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. > * > * This code is free software; you can redistribute it and/or modify it > * under the terms of the GNU General Public License version 2 only, as > * published by the Free Software Foundation. > * > * This code is distributed in the hope that it will be useful, but WITHOUT > * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > * version 2 for more details (a copy is included in the LICENSE file that > * accompanied this code). > * > * You should have received a copy of the GNU General Public License > version > * 2 along with this work; if not, write to the Free Software Foundation, > * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. > * > * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA > * or visit www.oracle.com if you need > additional information or have any > * questions. > */ > > import java.awt.BasicStroke; > import java.awt.Color; > import java.awt.Font; > import java.awt.Graphics2D; > import java.awt.RenderingHints; > import java.awt.font.FontRenderContext; > import java.awt.font.GlyphVector; > import java.awt.geom.AffineTransform; > import java.awt.image.BufferedImage; > import java.io.File; > import java.io.IOException; > import javax.imageio.ImageIO; > > /** > * @test > * @summary Check the Stroker.drawBezApproxForArc() bug: > * abs(cosext2) > 0.5 generates curves with NaN coordinates > * @run main TextClipErrorTest > */ > public class TextClipErrorTest { > > public static void main(String[] args) { > BufferedImage image = new BufferedImage(256, 256, > BufferedImage.TYPE_INT_ARGB); > > Graphics2D g2d = image.createGraphics(); > g2d.setColor(Color.red); > try { > g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, > RenderingHints.VALUE_ANTIALIAS_ON); > > Font font = g2d.getFont(); > FontRenderContext frc = new FontRenderContext( > new AffineTransform(), true, true); > > GlyphVector gv1 = font.createGlyphVector(frc, "\u00d6"); > > g2d.setStroke(new BasicStroke(4.0f, > BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); > > AffineTransform at1 = AffineTransform.getTranslateInstance( > -2091202.554154681, 5548.601436981691); > g2d.draw(at1.createTransformedShape(gv1.getOutline())); > > GlyphVector gv2 = font.createGlyphVector(frc, "Test 2"); > > AffineTransform at2 = AffineTransform.getTranslateInstance( > // -218.1810476789251, 85.12774919422463); > 10, 50); > g2d.draw(at2.createTransformedShape(gv2.getOutline())); > > > final File file = new File("TextClipErrorTest.png"); > System.out.println("Writing file: " + file.getAbsolutePath()); > ImageIO.write(image, "PNG", file); > > } catch (IOException ex) { > ex.printStackTrace(); > } > finally { > g2d.dispose(); > } > } > } > > > Cheers, > Laurent From bourges.laurent at gmail.com Wed Dec 9 06:07:27 2015 From: bourges.laurent at gmail.com (=?UTF-8?Q?Laurent_Bourg=C3=A8s?=) Date: Wed, 9 Dec 2015 07:07:27 +0100 Subject: [OpenJDK Rasterizer] AWT & gcc 4.8 optimization options In-Reply-To: <5658396E.2090605@oracle.com> References: <5627E1B0.4060206@oracle.com> <5658396E.2090605@oracle.com> Message-ID: Hi Sergey, Do you have made some progress ? If you modify the Maskfill C code, could you explain me how it works as I would like implementing in the future the correct gamma correction in this software loop ? Could you help me on this task Cheers, Laurent Le 27 nov. 2015 12:07, "Sergey Bylokhov" a ?crit : > > Right now I am trying to investigate where the code is affected by these options, and also I am trying to investigate possibility of code improvement. > > > On 27.11.15 13:28, Laurent Bourg?s wrote: >> >> Hi, >> >> Just a reminder on this compiler issue. >> >> I tested today the impact of the proposed patch changing compiler >> options for AWT on my machine (i7 gcc 4.8.4): >> >> Without patch (clean build - client libs): >> EllipseTests-fill-true.ser 1 25 445.220 >> 445.336 445.196 0.127 444.944 445.543 25 >> >> With patch: >> EllipseTests-fill-true.ser 1 26 402.889 >> 403.861 403.134 0.446 402.603 404.294 26 >> >> The impact is very important on this test (large mask fills) ~ 10% >> >> Sergey, could you check on gcc 4.9.2 ? >> >> Laurent >> >> 2015-10-21 21:04 GMT+02:00 Sergey Bylokhov > >: >> >> >> The bug was filed: >> https://bugs.openjdk.java.net/browse/JDK-8140266 >> >> I will try a few steps before push the current solution: >> - change the code, so this option will not be necessary. >> - check other compilers, it seems gcc 4.9.2 will be default for jdk9. >> > > > -- > Best regards, Sergey. -------------- next part -------------- An HTML attachment was scrubbed... URL: From Sergey.Bylokhov at oracle.com Wed Dec 9 14:43:04 2015 From: Sergey.Bylokhov at oracle.com (Sergey Bylokhov) Date: Wed, 9 Dec 2015 17:43:04 +0300 Subject: [OpenJDK Rasterizer] AWT & gcc 4.8 optimization options In-Reply-To: References: <5627E1B0.4060206@oracle.com> <5658396E.2090605@oracle.com> Message-ID: <56683DF8.1020607@oracle.com> On 09/12/15 09:07, Laurent Bourg?s wrote: > Hi Sergey, > > Do you have made some progress ? > > If you modify the Maskfill C code, could you explain me how it works as > I would like implementing in the future the correct gamma correction in > this software loop ? From the current source code point of view it is not an easy task to understand how it works. The easiest way to study it is to compile the jdk using this option in AWT2dLibraries.gmk --- a/make/lib/Awt2dLibraries.gmk Tue Dec 08 19:50:14 2015 +0300 +++ b/make/lib/Awt2dLibraries.gmk Wed Dec 09 17:10:55 2015 +0300 @@ -242,7 +242,7 @@ EXCLUDES := $(LIBAWT_EXCLUDES), \ EXCLUDE_FILES := $(LIBAWT_EXFILES), \ OPTIMIZATION := LOW, \ - CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS), \ + CFLAGS := -save-temps $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS), \ DISABLED_WARNINGS_gcc := sign-compare unused-result maybe-uninitialized \ format-nonliteral parentheses, \ DISABLED_WARNINGS_clang := logical-op-parentheses extern-initializer, \ This will save result of preprocessor. Also it will save an assembler code which can be useful to investigate how the compiler optimize the code, especially in case of vectorization. When you take a look to the code after preprocessor you will be able to understand the DSL which is used in the AlphaMacros.h for the "DEFINE_ALPHA_MASKBLIT" There are a bunch of files in the java.desktop/share/native/libawt/java2d/loops/. Some of them have the general code like LoopMacros.h, AlphaMacros.h, others have implementation for a some specific types. For example take a look to the IntRgb.c It have 2 parts: - The array IntRgbPrimitives, which contain the list of supported operations(it will register the functions which should be called in MaskBlit.c for some particular types). For example it contains REGISTER_ALPHA_MASKBLIT from/to a different types. - Definitions of the functions like DEFINE_SRCOVER_MASKBLIT(IntArgb, IntRgb, 4ByteArgb); This macros provide a function which will support the maskblit IntArgb->IntRgb; So to understand how it work you need to trace these calls: - MaskBlit.java -> MaskBlit(.....) - MaskBlit.c -> *pPrim->funcs.maskblit - The function which is generated from the DEFINE_SRCOVER_MASKBLIT for a particular type. Note that if for some reason we have no specific implementation of DEFINE_SRCOVER_MASKBLIT will meant that General MaskBlit from the MaskBlit.java will be used and it is quite slow. I am on the road of investigation... > > Could you help me on this task > > Cheers, > Laurent > > Le 27 nov. 2015 12:07, "Sergey Bylokhov" > a ?crit : > > > > Right now I am trying to investigate where the code is affected by > these options, and also I am trying to investigate possibility of code > improvement. > > > > > > On 27.11.15 13:28, Laurent Bourg?s wrote: > >> > >> Hi, > >> > >> Just a reminder on this compiler issue. > >> > >> I tested today the impact of the proposed patch changing compiler > >> options for AWT on my machine (i7 gcc 4.8.4): > >> > >> Without patch (clean build - client libs): > >> EllipseTests-fill-true.ser 1 25 445.220 > >> 445.336 445.196 0.127 444.944 445.543 25 > >> > >> With patch: > >> EllipseTests-fill-true.ser 1 26 402.889 > >> 403.861 403.134 0.446 402.603 404.294 26 > >> > >> The impact is very important on this test (large mask fills) ~ 10% > >> > >> Sergey, could you check on gcc 4.9.2 ? > >> > >> Laurent > >> > >> 2015-10-21 21:04 GMT+02:00 Sergey Bylokhov > > >> >>: > >> > >> > >> The bug was filed: > >> https://bugs.openjdk.java.net/browse/JDK-8140266 > >> > >> I will try a few steps before push the current solution: > >> - change the code, so this option will not be necessary. > >> - check other compilers, it seems gcc 4.9.2 will be default for > jdk9. > >> > > > > > > -- > > Best regards, Sergey. > -- Best regards, Sergey. From bourges.laurent at gmail.com Thu Dec 10 09:24:47 2015 From: bourges.laurent at gmail.com (=?UTF-8?Q?Laurent_Bourg=C3=A8s?=) Date: Thu, 10 Dec 2015 10:24:47 +0100 Subject: [OpenJDK Rasterizer] AWT & gcc 4.8 optimization options In-Reply-To: <56683DF8.1020607@oracle.com> References: <5627E1B0.4060206@oracle.com> <5658396E.2090605@oracle.com> <56683DF8.1020607@oracle.com> Message-ID: Sergey, Thanks a lot for your advices, I will definitely try your approach to read the 'preprocessed' C code (as I do not like much macros). I think I will have some time during winter holidays to implement correct gamma correction = pow(2.2), blend then pow(1/2.2) (using precomputed tables) in that C code. If you modify the Maskfill C code, could you explain me how it works as >> I would like implementing in the future the correct gamma correction in >> this software loop ? >> > > From the current source code point of view it is not an easy task to > understand how it works. The easiest way to study it is to compile the jdk > using this option in AWT2dLibraries.gmk > > --- a/make/lib/Awt2dLibraries.gmk Tue Dec 08 19:50:14 2015 +0300 > +++ b/make/lib/Awt2dLibraries.gmk Wed Dec 09 17:10:55 2015 +0300 > @@ -242,7 +242,7 @@ > EXCLUDES := $(LIBAWT_EXCLUDES), \ > EXCLUDE_FILES := $(LIBAWT_EXFILES), \ > OPTIMIZATION := LOW, \ > - CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS), \ > + CFLAGS := -save-temps $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS), \ > DISABLED_WARNINGS_gcc := sign-compare unused-result maybe-uninitialized \ > format-nonliteral parentheses, \ > DISABLED_WARNINGS_clang := logical-op-parentheses extern-initializer, \ > > This will save result of preprocessor. Also it will save an assembler code > which can be useful to investigate how the compiler optimize the code, > especially in case of vectorization. > > When you take a look to the code after preprocessor you will be able to > understand the DSL which is used in the AlphaMacros.h for the > "DEFINE_ALPHA_MASKBLIT" > > > There are a bunch of files in the > java.desktop/share/native/libawt/java2d/loops/. Some of them have the > general code like LoopMacros.h, AlphaMacros.h, others have implementation > for a some specific types. > > > For example take a look to the IntRgb.c > It have 2 parts: > - The array IntRgbPrimitives, which contain the list of supported > operations(it will register the functions which should be called in > MaskBlit.c for some particular types). For example it contains > REGISTER_ALPHA_MASKBLIT from/to a different types. > - Definitions of the functions like DEFINE_SRCOVER_MASKBLIT(IntArgb, > IntRgb, 4ByteArgb); This macros provide a function which will support the > maskblit IntArgb->IntRgb; > > So to understand how it work you need to trace these calls: > - MaskBlit.java -> MaskBlit(.....) > - MaskBlit.c -> *pPrim->funcs.maskblit > - The function which is generated from the DEFINE_SRCOVER_MASKBLIT for a > particular type. > > Note that if for some reason we have no specific implementation of > DEFINE_SRCOVER_MASKBLIT will meant that General MaskBlit from the > MaskBlit.java will be used and it is quite slow. > > I am on the road of investigation... > Excellent ! Maybe you should compare the preprocessor outputs between gcc 4.3.2 (JDK8) that was faster than gcc 4.8.4 (JDK9) ! I guess it is related to the loop vectorization (simd) that seems slower in gcc >= 4.4 (known regression ?) Good luck & keep me informed about your investigations, Laurent -------------- next part -------------- An HTML attachment was scrubbed... URL: