aboutsummaryrefslogtreecommitdiff
path: root/src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java')
-rw-r--r--src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java349
1 files changed, 349 insertions, 0 deletions
diff --git a/src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java b/src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java
new file mode 100644
index 000000000..218386ffe
--- /dev/null
+++ b/src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.java2d.jules;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.concurrent.*;
+import sun.java2d.pipe.*;
+import sun.java2d.xr.*;
+
+public class JulesAATileGenerator implements AATileGenerator {
+ /* Threading stuff */
+ final static ExecutorService rasterThreadPool =
+ Executors.newCachedThreadPool();
+ final static int CPU_CNT = Runtime.getRuntime().availableProcessors();
+
+ final static boolean ENABLE_THREADING = false;
+ final static int THREAD_MIN = 16;
+ final static int THREAD_BEGIN = 16;
+
+ IdleTileCache tileCache;
+ TileWorker worker;
+ boolean threaded = false;
+ int rasterTileCnt;
+
+ /* Tiling */
+ final static int TILE_SIZE = 32;
+ final static int TILE_SIZE_FP = 32 << 16;
+ int left, right, top, bottom, width, height;
+ int leftFP, topFP;
+ int tileCnt, tilesX, tilesY;
+ int currTilePos = 0;
+ TrapezoidList traps;
+ TileTrapContainer[] tiledTrapArray;
+ JulesTile mainTile;
+
+ public JulesAATileGenerator(Shape s, AffineTransform at, Region clip,
+ BasicStroke bs, boolean thin,
+ boolean normalize, int[] bbox) {
+ JulesPathBuf buf = new JulesPathBuf();
+
+ if (bs == null) {
+ traps = buf.tesselateFill(s, at, clip);
+ } else {
+ traps = buf.tesselateStroke(s, bs, thin, false, true, at, clip);
+ }
+
+ calculateArea(bbox);
+ bucketSortTraps();
+ calculateTypicalAlpha();
+
+ threaded = ENABLE_THREADING &&
+ rasterTileCnt >= THREAD_MIN && CPU_CNT >= 2;
+ if (threaded) {
+ tileCache = new IdleTileCache();
+ worker = new TileWorker(this, THREAD_BEGIN, tileCache);
+ rasterThreadPool.execute(worker);
+ }
+
+ mainTile = new JulesTile();
+ }
+
+ private static native long
+ rasterizeTrapezoidsNative(long pixmanImagePtr, int[] traps,
+ int[] trapPos, int trapCnt,
+ byte[] buffer, int xOff, int yOff);
+
+ private static native void freePixmanImgPtr(long pixmanImgPtr);
+
+ private void calculateArea(int[] bbox) {
+ tilesX = 0;
+ tilesY = 0;
+ tileCnt = 0;
+ bbox[0] = 0;
+ bbox[1] = 0;
+ bbox[2] = 0;
+ bbox[3] = 0;
+
+ if (traps.getSize() > 0) {
+ left = traps.getLeft();
+ right = traps.getRight();
+ top = traps.getTop();
+ bottom = traps.getBottom();
+ leftFP = left << 16;
+ topFP = top << 16;
+
+ bbox[0] = left;
+ bbox[1] = top;
+ bbox[2] = right;
+ bbox[3] = bottom;
+
+ width = right - left;
+ height = bottom - top;
+
+ if (width > 0 && height > 0) {
+ tilesX = (int) Math.ceil(((double) width) / TILE_SIZE);
+ tilesY = (int) Math.ceil(((double) height) / TILE_SIZE);
+ tileCnt = tilesY * tilesX;
+ tiledTrapArray = new TileTrapContainer[tileCnt];
+ } else {
+ // If there is no area touched by the traps, don't
+ // render them.
+ traps.setSize(0);
+ }
+ }
+ }
+
+
+ private void bucketSortTraps() {
+
+ for (int i = 0; i < traps.getSize(); i++) {
+ int top = traps.getTop(i) - XRUtils.XDoubleToFixed(this.top);
+ int bottom = traps.getBottom(i) - topFP;
+ int p1xLeft = traps.getP1XLeft(i) - leftFP;
+ int p2xLeft = traps.getP2XLeft(i) - leftFP;
+ int p1xRight = traps.getP1XRight(i) - leftFP;
+ int p2xRight = traps.getP2XRight(i) - leftFP;
+
+ int minLeft = Math.min(p1xLeft, p2xLeft);
+ int maxRight = Math.max(p1xRight, p2xRight);
+
+ maxRight = maxRight > 0 ? maxRight - 1 : maxRight;
+ bottom = bottom > 0 ? bottom - 1 : bottom;
+
+ int startTileY = top / TILE_SIZE_FP;
+ int endTileY = bottom / TILE_SIZE_FP;
+ int startTileX = minLeft / TILE_SIZE_FP;
+ int endTileX = maxRight / TILE_SIZE_FP;
+
+ for (int n = startTileY; n <= endTileY; n++) {
+
+ for (int m = startTileX; m <= endTileX; m++) {
+ int trapArrayPos = n * tilesX + m;
+ TileTrapContainer trapTileList = tiledTrapArray[trapArrayPos];
+ if (trapTileList == null) {
+ trapTileList = new TileTrapContainer(new GrowableIntArray(1, 16));
+ tiledTrapArray[trapArrayPos] = trapTileList;
+ }
+
+ trapTileList.getTraps().addInt(i);
+ }
+ }
+ }
+ }
+
+ public void getAlpha(byte[] tileBuffer, int offset, int rowstride) {
+ JulesTile tile = null;
+
+ if (threaded) {
+ tile = worker.getPreRasterizedTile(currTilePos);
+ }
+
+ if (tile != null) {
+ System.arraycopy(tile.getImgBuffer(), 0,
+ tileBuffer, 0, tileBuffer.length);
+ tileCache.releaseTile(tile);
+ } else {
+ mainTile.setImgBuffer(tileBuffer);
+ rasterizeTile(currTilePos, mainTile);
+ }
+
+ nextTile();
+ }
+
+ public void calculateTypicalAlpha() {
+ rasterTileCnt = 0;
+
+ for (int index = 0; index < tileCnt; index++) {
+
+ TileTrapContainer trapCont = tiledTrapArray[index];
+ if (trapCont != null) {
+ GrowableIntArray trapList = trapCont.getTraps();
+
+ int tileAlpha = 127;
+ if (trapList == null || trapList.getSize() == 0) {
+ tileAlpha = 0;
+ } else if (doTrapsCoverTile(trapList, index)) {
+ tileAlpha = 0xff;
+ }
+
+ if (tileAlpha == 127 || tileAlpha == 0xff) {
+ rasterTileCnt++;
+ }
+
+ trapCont.setTileAlpha(tileAlpha);
+ }
+ }
+ }
+
+ /*
+ * Optimization for large fills. Foutunatly cairo does generate an y-sorted
+ * list of trapezoids. This makes it quite simple to check wether a tile is
+ * fully covered by traps by: - Checking wether the tile is fully covered by
+ * traps vertically (trap 2 starts where trap 1 ended) - Checking wether all
+ * traps cover the tile horizontally This also works, when a single tile
+ * coveres the whole tile.
+ */
+ protected boolean doTrapsCoverTile(GrowableIntArray trapList, int tileIndex) {
+
+ // Don't bother optimizing tiles with lots of traps, usually it won't
+ // succeed anyway.
+ if (trapList.getSize() > TILE_SIZE) {
+ return false;
+ }
+
+ int tileStartX = getXPos(tileIndex) * TILE_SIZE_FP + leftFP;
+ int tileStartY = getYPos(tileIndex) * TILE_SIZE_FP + topFP;
+ int tileEndX = tileStartX + TILE_SIZE_FP;
+ int tileEndY = tileStartY + TILE_SIZE_FP;
+
+ // Check wether first tile covers the beginning of the tile vertically
+ int firstTop = traps.getTop(trapList.getInt(0));
+ int firstBottom = traps.getBottom(trapList.getInt(0));
+ if (firstTop > tileStartY || firstBottom < tileStartY) {
+ return false;
+ }
+
+ // Initialize lastBottom with top, in order to pass the checks for the
+ // first iteration
+ int lastBottom = firstTop;
+
+ for (int i = 0; i < trapList.getSize(); i++) {
+ int trapPos = trapList.getInt(i);
+ if (traps.getP1XLeft(trapPos) > tileStartX ||
+ traps.getP2XLeft(trapPos) > tileStartX ||
+ traps.getP1XRight(trapPos) < tileEndX ||
+ traps.getP2XRight(trapPos) < tileEndX ||
+ traps.getTop(trapPos) != lastBottom)
+ {
+ return false;
+ }
+ lastBottom = traps.getBottom(trapPos);
+ }
+
+ // When the last trap covered the tileEnd vertically, the tile is fully
+ // covered
+ return lastBottom >= tileEndY;
+ }
+
+ public int getTypicalAlpha() {
+ if (tiledTrapArray[currTilePos] == null) {
+ return 0;
+ } else {
+ return tiledTrapArray[currTilePos].getTileAlpha();
+ }
+ }
+
+ public void dispose() {
+ freePixmanImgPtr(mainTile.getPixmanImgPtr());
+
+ if (threaded) {
+ tileCache.disposeConsumerResources();
+ worker.disposeConsumerResources();
+ }
+ }
+
+ protected JulesTile rasterizeTile(int tileIndex, JulesTile tile) {
+ int tileOffsetX = left + getXPos(tileIndex) * TILE_SIZE;
+ int tileOffsetY = top + getYPos(tileIndex) * TILE_SIZE;
+ TileTrapContainer trapCont = tiledTrapArray[tileIndex];
+ GrowableIntArray trapList = trapCont.getTraps();
+
+ if (trapCont.getTileAlpha() == 127) {
+ long pixmanImgPtr =
+ rasterizeTrapezoidsNative(tile.getPixmanImgPtr(),
+ traps.getTrapArray(),
+ trapList.getArray(),
+ trapList.getSize(),
+ tile.getImgBuffer(),
+ tileOffsetX, tileOffsetY);
+ tile.setPixmanImgPtr(pixmanImgPtr);
+ }
+
+ tile.setTilePos(tileIndex);
+ return tile;
+ }
+
+ protected int getXPos(int arrayPos) {
+ return arrayPos % tilesX;
+ }
+
+ protected int getYPos(int arrayPos) {
+ return arrayPos / tilesX;
+ }
+
+ public void nextTile() {
+ currTilePos++;
+ }
+
+ public int getTileHeight() {
+ return TILE_SIZE;
+ }
+
+ public int getTileWidth() {
+ return TILE_SIZE;
+ }
+
+ public int getTileCount() {
+ return tileCnt;
+ }
+
+ public TileTrapContainer getTrapContainer(int index) {
+ return tiledTrapArray[index];
+ }
+}
+
+class TileTrapContainer {
+ int tileAlpha;
+ GrowableIntArray traps;
+
+ public TileTrapContainer(GrowableIntArray traps) {
+ this.traps = traps;
+ }
+
+ public void setTileAlpha(int tileAlpha) {
+ this.tileAlpha = tileAlpha;
+ }
+
+ public int getTileAlpha() {
+ return tileAlpha;
+ }
+
+ public GrowableIntArray getTraps() {
+ return traps;
+ }
+}