bourgesl / marlin-renderer

Marlin is the FAST Java2D antialiasing rasterizer derived from OpenJDK Pisces (shape)
Other
180 stars 17 forks source link

-Dsun.java2d.renderer.doChecks=true flag don't work #5

Closed jandam closed 8 years ago

jandam commented 8 years ago

Marlin 7.2.1 says sun.java2d.renderer.doChecks=false when I set value to true.

-Dsun.java2d.renderer.doChecks=true

I have rendering artifacts that I can't debug. (Marlin 7.1, 7.2x)

For example -Dsun.java2d.renderer.useLogger=true works correctly.

bourgesl commented 8 years ago

Hi, I just fixed it and I updated the released jars v0.7.2.1: https://github.com/bourgesl/marlin-renderer/releases/tag/v0.7.2.1

Please give me more details on the artifacts, please !

In Marlin 0.7.1+, I now implemented a new RLE encoding approach for huge shapes that may have bugs although I tested several maps (regression tests).

Could you send me a screenshot or an image diff ?

Laurent

jandam commented 8 years ago

Thank you latest version works and I got following stack trace Java8u65, Marlin 0.7.2.1: java.lang.Throwable at org.marlin.pisces.IntArrayCache.check(IntArrayCache.java:139) at org.marlin.pisces.IntArrayCache.fill(IntArrayCache.java:128) at org.marlin.pisces.Renderer.dispose(Renderer.java:634) at org.marlin.pisces.MarlinRenderingEngine.getAATileGenerator(MarlinRenderingEngine.java:765) at sun.java2d.pipe.AAShapePipe.renderPath(AAShapePipe.java:152) at sun.java2d.pipe.AAShapePipe.draw(AAShapePipe.java:64) at sun.java2d.pipe.PixelToParallelogramConverter.draw(PixelToParallelogramConverter.java:148) at sun.java2d.pipe.ValidatePipe.draw(ValidatePipe.java:154) at sun.java2d.SunGraphics2D.draw(SunGraphics2D.java:2497)

WARNING: Invalid array value at 0 [14, 0, 0, 0, .... I draw stroked glyph vector to INT_ARGB buffered image:

    FontRenderContext fontRenderContext = new FontRenderContext(new AffineTransform(), true, true);
        GlyphVector gv = font.createGlyphVector(fontRenderContext, text);
            Shape outline = gv.getOutline();
                g2.setColor(color);
                g2.setStroke(stroke);
                g2.draw(outline);
bourgesl commented 8 years ago

Could you give me a working test that reproduces the bug ? or at least an image that illustrates that case.

According to the traces, the problem concerns: // fill only used part 634: IntArrayCache.fill(edgeBuckets, buckets_minY, buckets_maxY, 0);

So the buckets_minY is wrong !

jandam commented 8 years ago

Drawing independent glyps don't work to: int numGlyphs = gv.getNumGlyphs(); for (int index = 0; index < numGlyphs; index++) { g2.draw(gv.getGlyphOutline(index)); }

Following code works correctly: g2.setColor(color); g2.setStroke(new BasicStroke(0.0f)); g2.fill(stroke.createStrokedShape(outline));

bourgesl commented 8 years ago

Sorry to ask again, but I am a bit lost.

I never played with glyph vector ... so please just give me a complete test method() that compiles and reproduces the problem.

I may try to create a test class for that purpose but it will be faster if you write it or at least the squeleton.

jandam commented 8 years ago

Looks like problem is in IntArrayCache method fill uses invalid range for checking. I have following parametes. SO check method should be called with range [fromIndex..toIndex] instead of range [0..array.length] Same issue is in ByteArrayCache, IntArrayCache and FloatArrayCache

array = {int[16385]@7610} fromIndex = 749 toIndex = 870 value = 0

 static void fill(int[] array, int fromIndex, int toIndex, int value) {
        if(toIndex != 0) {
            Arrays.fill(array, fromIndex, toIndex, value);
        }

        if(doChecks) {
            check(array, 0, array.length, value);
        }

    }
jandam commented 8 years ago

Necessary condition to reproduce this issue is that Min Y of transformed bounds to image coordinate system must be greater that image height Rectangle2D bounds = g2.getTransform().createTransformedShape(outline).getBounds2D(); bounds2D.getMinY() >= image.getHeight()

bourgesl commented 8 years ago

For performance reasons, I do partial array cleanup! It's tricky but the edge bucket arrays MUST be 0 filled in all range !

If doChecks reports an error then it must be fixed but may be related to previous operations too = very difficult to debug !

I really need reproducing the test.

Could you send me some code and your logs to bourges.laurent at gmail ?

jandam commented 8 years ago

OK. I will try to make small test tomorrow morning. Today I have to go :-(

jandam commented 8 years ago

Hi I have small test for this issue: Problem occurs during rendering FIRST glyph vector that leaves non zero value on first index in Renderer.edgeBuckets. Stroker.drawBezApproxForArc computes value 'cv' as NaN. It is during rendering "quadTo" with JOIN_ROUND. Glyph vector is completely outside buffered image area. When I disable antialiasing or round join everything works.

  BufferedImage bi = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);  // can be TYPE_INT_ARGB
        Graphics2D g2 = bi.createGraphics();
        try {
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            Font font = g2.getFont();
            FontRenderContext fontRenderContext = new FontRenderContext(new AffineTransform(), true, true);
            GlyphVector gv1 = font.createGlyphVector(fontRenderContext, "\u00d6");

            g2.setStroke(new BasicStroke(4.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            AffineTransform at1 = AffineTransform.getTranslateInstance( -2091202.554154681, 5548.601436981691);
            g2.draw(at1.createTransformedShape(gv1.getOutline()));

            GlyphVector gv2 = font.createGlyphVector(fontRenderContext, "Test 2");
            AffineTransform at2 = AffineTransform.getTranslateInstance( -218.1810476789251,  85.12774919422463);
            g2.draw(at2.createTransformedShape(gv2.getOutline()));
        } finally {
            g2.dispose();
        }
bourgesl commented 8 years ago

Congratulations !

I reproduce the problem and your diagnostic is exact:

I will look at maths to understand what does it mean but I suspect a float precision issue: it happens when the translation is large >2e6.

I will clamp that value in [-0.5,0.5] to avoid NaN first and also submit that bug to OpenJDK pisces.

Thanks again

bourgesl commented 8 years ago

Fix pushed in the use_Unsafe branch.

I also added your test code.

Will make a new release soon

jandam commented 8 years ago

Thank you for fast fix of the issue

bourgesl commented 8 years ago

FYI I will submit a bug to openjdk asap. Could you give me your full name to mention in the test class header ?

Do you need a release ?

Thanks a lot to have reported this long-standing issue.

Laurent

jandam commented 8 years ago

I updated my profile on GitHub. New release will be nice. M

bourgesl commented 8 years ago

Thanks, I updated the @author tag in TextClipErrorTest.

Here is the release v0.7.3: https://github.com/bourgesl/marlin-renderer/releases/tag/v0.7.3

bourgesl commented 8 years ago

See https://bugs.openjdk.java.net/browse/JDK-8144718