jdk-24/jdk/test/sun/java2d/marlin/CrashTest.java
Laurent Bourgès 155cc1f5bc 8143849: Integrate Marlin renderer per JEP 265
Reviewed-by: flar, prr
2015-11-23 15:02:19 -08:00

290 lines
9.8 KiB
Java

/*
* 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.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import static java.awt.geom.Path2D.WIND_NON_ZERO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import sun.java2d.pipe.RenderingEngine;
/**
* Simple crash rendering test using huge GeneralPaths with marlin renderer
*
* run it with large heap (2g):
* java -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine marlin.CrashTest
*
* @author bourgesl
*/
public class CrashTest {
static final boolean SAVE_IMAGE = false;
static boolean USE_ROUND_CAPS_AND_JOINS = true;
public static void main(String[] args) {
// try insane image sizes:
// subpixel coords may overflow:
// testHugeImage((Integer.MAX_VALUE >> 3) + 1, 6);
// larger than 23 bits: (RLE)
testHugeImage(8388608 + 1, 10);
test(0.1f, false, 0);
test(0.1f, true, 7f);
// Exceed 2Gb OffHeap buffer for edges:
try {
USE_ROUND_CAPS_AND_JOINS = true;
test(0.1f, true, 0.1f);
System.out.println("Exception MISSING.");
}
catch (Throwable th) {
if (th instanceof ArrayIndexOutOfBoundsException) {
System.out.println("ArrayIndexOutOfBoundsException expected.");
} else {
System.out.println("Exception occured:");
th.printStackTrace();
}
}
}
private static void test(final float lineStroke,
final boolean useDashes,
final float dashMinLen)
throws ArrayIndexOutOfBoundsException
{
System.out.println("---\n" + "test: "
+ "lineStroke=" + lineStroke
+ ", useDashes=" + useDashes
+", dashMinLen=" + dashMinLen
);
final String renderer = RenderingEngine.getInstance().getClass().getSimpleName();
System.out.println("Testing renderer = " + renderer);
final BasicStroke stroke = createStroke(lineStroke, useDashes, dashMinLen);
// TODO: test Dasher.firstSegmentsBuffer resizing ?
// array.dasher.firstSegmentsBuffer.d_float[2] sum: 6 avg: 3.0 [3 | 3]
/*
// Marlin growable arrays:
= new StatLong("array.dasher.firstSegmentsBuffer.d_float");
= new StatLong("array.stroker.polystack.curves.d_float");
= new StatLong("array.stroker.polystack.curveTypes.d_byte");
= new StatLong("array.marlincache.rowAAChunk.d_byte");
= new StatLong("array.marlincache.touchedTile.int");
= new StatLong("array.renderer.alphaline.int");
= new StatLong("array.renderer.crossings.int");
= new StatLong("array.renderer.aux_crossings.int");
= new StatLong("array.renderer.edgeBuckets.int");
= new StatLong("array.renderer.edgeBucketCounts.int");
= new StatLong("array.renderer.edgePtrs.int");
= new StatLong("array.renderer.aux_edgePtrs.int");
*/
// size > 8192 (exceed both tile and buckets arrays)
final int size = 9000;
System.out.println("image size = " + size);
final BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = (Graphics2D) image.getGraphics();
try {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setClip(0, 0, size, size);
g2d.setBackground(Color.WHITE);
g2d.clearRect(0, 0, size, size);
g2d.setStroke(stroke);
g2d.setColor(Color.BLACK);
final long start = System.nanoTime();
paint(g2d, size - 10f);
final long time = System.nanoTime() - start;
System.out.println("paint: duration= " + (1e-6 * time) + " ms.");
if (SAVE_IMAGE) {
try {
final File file = new File("CrashTest-" + renderer + "-dash-" + useDashes + ".bmp");
System.out.println("Writing file: " + file.getAbsolutePath());
ImageIO.write(image, "BMP", file);
} catch (IOException ex) {
System.out.println("Writing file failure:");
ex.printStackTrace();
}
}
} finally {
g2d.dispose();
}
}
private static void testHugeImage(final int width, final int height)
throws ArrayIndexOutOfBoundsException
{
System.out.println("---\n" + "testHugeImage: "
+ "width=" + width
+ ", height=" + height
);
final String renderer = RenderingEngine.getInstance().getClass().getSimpleName();
System.out.println("Testing renderer = " + renderer);
final BasicStroke stroke = createStroke(2.5f, false, 0);
// size > 24bits (exceed both tile and buckets arrays)
System.out.println("image size = " + width + " x "+height);
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
final Graphics2D g2d = (Graphics2D) image.getGraphics();
try {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setBackground(Color.WHITE);
g2d.clearRect(0, 0, width, height);
g2d.setStroke(stroke);
g2d.setColor(Color.BLACK);
final Path2D.Float path = new Path2D.Float(WIND_NON_ZERO, 32);
path.moveTo(0, 0);
path.lineTo(width, 0);
path.lineTo(width, height);
path.lineTo(0, height);
path.lineTo(0, 0);
final long start = System.nanoTime();
g2d.draw(path);
final long time = System.nanoTime() - start;
System.out.println("paint: duration= " + (1e-6 * time) + " ms.");
if (SAVE_IMAGE) {
try {
final File file = new File("CrashTest-" + renderer +
"-huge-" + width + "x" +height + ".bmp");
System.out.println("Writing file: " + file.getAbsolutePath());
ImageIO.write(image, "BMP", file);
} catch (IOException ex) {
System.out.println("Writing file failure:");
ex.printStackTrace();
}
}
} finally {
g2d.dispose();
}
}
private static void paint(final Graphics2D g2d, final float size) {
final double halfSize = size / 2.0;
final Path2D.Float path = new Path2D.Float(WIND_NON_ZERO, 32 * 1024);
// show cross:
path.moveTo(0, 0);
path.lineTo(size, size);
path.moveTo(size, 0);
path.lineTo(0, size);
path.moveTo(0, 0);
path.lineTo(size, 0);
path.moveTo(0, 0);
path.lineTo(0, size);
path.moveTo(0, 0);
double r = size;
final int ratio = 100;
int repeats = 1;
int n = 0;
while (r > 1.0) {
repeats *= ratio;
if (repeats > 10000) {
repeats = 10000;
}
for (int i = 0; i < repeats; i++) {
path.lineTo(halfSize - 0.5 * r + i * r / repeats,
halfSize - 0.5 * r);
n++;
path.lineTo(halfSize - 0.5 * r + i * r / repeats + 0.1,
halfSize + 0.5 * r);
n++;
}
r -= halfSize;
}
System.out.println("draw : " + n + " lines.");
g2d.draw(path);
}
private static BasicStroke createStroke(final float width,
final boolean useDashes,
final float dashMinLen) {
final float[] dashes;
if (useDashes) {
// huge dash array (exceed Dasher.INITIAL_ARRAY)
dashes = new float[512];
float cur = dashMinLen;
float step = 0.01f;
for (int i = 0; i < dashes.length; i += 2) {
dashes[i] = cur;
dashes[i + 1] = cur;
cur += step;
}
} else {
dashes = null;
}
if (USE_ROUND_CAPS_AND_JOINS) {
// Use both round Caps & Joins:
return new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 100.0f, dashes, 0.0f);
}
return new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 100.0f, dashes, 0.0f);
}
}