diff -r a92ec8090ae5 pisces/src/com/sun/openpisces/Renderer.java --- a/pisces/src/com/sun/openpisces/Renderer.java Thu May 31 11:37:22 2012 -0400 +++ b/pisces/src/com/sun/openpisces/Renderer.java Mon Jun 11 13:47:09 2012 -0400 @@ -334,8 +334,13 @@ // Position of most recent 'moveTo' command private float pix_sx0, pix_sy0; + int subpixelLgPositionsX; + int subpixelLgPositionsY; public Renderer(int subpixelLgPositionsX, int subpixelLgPositionsY) { + this.subpixelLgPositionsX = subpixelLgPositionsX; + this.subpixelLgPositionsY = subpixelLgPositionsY; + this.SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX; this.SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY; this.SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X); @@ -442,7 +447,27 @@ public void pathDone() { closePath(); } - + + public void init(AlphaConsumer ac) { + ScanlineIterator2.init0(subpixelLgPositionsX, subpixelLgPositionsY); + ac.setMaxAlpha(MAX_AA_ALPHA); + } + public void produceAlphas2(AlphaConsumer ac, byte [] alphas, byte [] map, int width, int y) { + ScanlineIterator2.produceAlphas(subpixelLgPositionsX, subpixelLgPositionsY, + windingRule, boundsMinY, sampleRowMin, sampleRowMax, edges, edgeBuckets, + alphas, alphas.length, map, width, y, ac.getOriginX()); + } + /* + public void init(AlphaConsumer ac) { + ScanlineIterator2.init02(subpixelLgPositionsX, subpixelLgPositionsY); + ac.setMaxAlpha(MAX_AA_ALPHA); + } + public void produceAlphas2(AlphaConsumer ac, byte [] alphas, byte [] map, int width, int y) { + ScanlineIterator2.produceAlphas2(subpixelLgPositionsX, subpixelLgPositionsY, + windingRule, boundsMinY, sampleRowMin, sampleRowMax, edges, edgeBuckets, + alphas, alphas.length, map, width, y, ac.getOriginX()); + } + */ private int savedAlpha[]; private ScanlineIterator savedIterator; public void produceAlphas(AlphaConsumer ac) { diff -r a92ec8090ae5 pisces/src/com/sun/openpisces/ScanlineIterator2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pisces/src/com/sun/openpisces/ScanlineIterator2.java Mon Jun 11 13:47:09 2012 -0400 @@ -0,0 +1,300 @@ +package com.sun.openpisces; + +import java.util.Arrays; +import static java.lang.Math.*; + + final class ScanlineIterator2 { + +/** Java stubs **/ + +static int[] new_int(int size) { + return new int [size]; +} +static void free(Object object) { + +} +static void fill (int [] a, int b, int c, int d) { + Arrays.fill(a, b, c, d); +} +static int[] widenArray(int[] in, int inSize, final int cursize, final int numToAdd) { + if (in.length >= cursize + numToAdd) { + return in; + } + return Arrays.copyOf(in, 2 * (cursize + numToAdd)); +} + +public static native void init0(int subpixelLgPositionsX, int subpixelLgPositionsY); +public static native void produceAlphas(int subpixelLgPositionsX, int subpixelLgPositionsY, + int windingRule, int boundsMinY, int sampleRowMin, int sampleRowMax, + float edges[], int edgeBuckets[], + byte alphas[], int alphasSize, byte alphaMap[], + int inWidth, int inY, int inOrigin); + +/*** C and Java Code ***/ + +private static final int YMAX = 0; +private static final int CURX = 1; +// NEXT and OR are meant to be indeces into "int" fields, but arrays must +// be homogenous, so every field is a float. However floats can represent +// exactly up to 26 bit ints, so we're ok. +private static final int OR = 2; +private static final int SLOPE = 3; +private static final int NEXT = 4; + +static private int[] crossings; +static private int crossingsSize; +static private int[] edgePtrs; +static private int edgeCount; +static private int edgeSize; + +// crossing bounds. The bounds are not necessarily tight (the scan line +// at minY, for example, might have no crossings). The x bounds will +// be accumulated as crossings are computed. +static private int nextY; + + +private static final int INIT_CROSSINGS_SIZE = 10; + + +public static void reset(int sampleRowMin) { + // We don't care if we clip some of the line off with ceil, since + // no scan line crossings will be eliminated (in fact, the ceil is + // the y of the first scan line crossing). + nextY = sampleRowMin; + edgeCount = 0; +} + +private static int next(int boundsMinY, float edges[], int edgeBuckets[]) { + // TODO: make function that convert from y value to bucket idx? + int cury = nextY++; + int bucket = cury - boundsMinY; + int count = edgeCount; + int[] ptrs = edgePtrs; + int bucketcount = edgeBuckets[bucket*2 + 1]; + if ((bucketcount & 0x1) != 0) { + int newCount = 0; + for (int i = 0; i < count; i++) { + int ecur = ptrs[i]; + if (edges[ecur+YMAX] > cury) { + ptrs[newCount++] = ecur; + } + } + count = newCount; + } + + //BAD - get rid of helper + ptrs = widenArray(ptrs, edgeSize, count, bucketcount >> 1); + if (ptrs != edgePtrs) { + edgeSize = 2 * (count + (bucketcount >> 1)); + } + + for (int ecur = edgeBuckets[bucket*2]; + ecur != 0; + ecur = (int)edges[ecur+NEXT]) + { + ptrs[count++] = --ecur; + // REMIND: Adjust start Y if necessary + } + edgePtrs = ptrs; + edgeCount = count; + // if ((count & 0x1) != 0) { + // System.out.println("ODD NUMBER OF EDGES!!!!"); + // } + int[] xings = crossings; + if (crossingsSize < count) { + xings = new_int(crossingsSize = edgeSize); + free(crossings); + crossings = xings; + } + for (int i = 0; i < count; i++) { + int ecur = ptrs[i]; + float curx = edges[ecur+CURX]; + int cross = ((int) curx) << 1; + edges[ecur+CURX] = curx + edges[ecur+SLOPE]; + if (edges[ecur+OR] > 0) { + cross |= 1; + } + int j = i; + while (--j >= 0) { + int jcross = xings[j]; + if (jcross <= cross) { + break; + } + xings[j+1] = jcross; + ptrs[j+1] = ptrs[j]; + } + xings[j+1] = cross; + ptrs[j+1] = ecur; + } + return count; +} + +private static boolean hasNext(int sampleRowMax) { + return nextY < sampleRowMax; +} + +private static int curY() { + return nextY - 1; +} + +public static final int WIND_EVEN_ODD = 0; +public static final int WIND_NON_ZERO = 1; + +//TODO -static is all wrong, subpixel not initialized properly + +/*final*/ private static int SUBPIXEL_LG_POSITIONS_X; +/*final*/ private static int SUBPIXEL_LG_POSITIONS_Y; +/*final*/ private static int SUBPIXEL_POSITIONS_X; +/*final*/ private static int SUBPIXEL_POSITIONS_Y; +/*final*/ private static int SUBPIXEL_MASK_X; +/*final*/ private static int SUBPIXEL_MASK_Y; +/*final*/ static int MAX_AA_ALPHA; + +static void init(int subpixelLgPositionsX, int subpixelLgPositionsY) +{ + /*this.*/SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX; + /*this.*/SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY; + /*this.*/SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X); + /*this.*/SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y); + /*this.*/SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1; + /*this.*/SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1; + /*this.*/MAX_AA_ALPHA = (SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y); +} + +static void new_ScanlineIterator2(int sampleRowMin, int subpixelLgPositionsX, int subpixelLgPositionsY) { + crossings = new_int(crossingsSize = INIT_CROSSINGS_SIZE); + edgePtrs = new_int(edgeSize = INIT_CROSSINGS_SIZE); + reset(sampleRowMin); + init(subpixelLgPositionsX, subpixelLgPositionsY); +} + +public static void init02(int subpixelLgPositionsX, int subpixelLgPositionsY) { + new_ScanlineIterator2(0, subpixelLgPositionsX, subpixelLgPositionsY); +} + +static void setAndClearRelativeAlphas(int alphaRow[], int pix_y, + int pix_from, int pix_to, byte alphas[], byte alphaMap[], int width, int y) +{ + // System.out.println("setting row "+(pix_y - y)+ + // " out of "+width+" x "+height); + int w = width; + int off = (pix_y - y) * w; + byte[] out = /*this*/alphas; + byte[] map = /*this*/alphaMap; + int a = 0; + for (int i = 0; i < w; i++) { + a += alphaRow[i]; + alphaRow[i] = 0; + out[off+i] = map[a]; + } +} + +static private int[] savedAlpha; +static private int savedAlphaSize; +public static void produceAlphas2(int subpixelLgPositionsX, int subpixelLgPositionsY, + int windingRule, int boundsMinY, int sampleRowMin, int sampleRowMax, + float edges[], int edgeBuckets[], + byte alphas[], int alphasSize, byte alphaMap[], + int inWidth, int inY, int inOrigin) { + + // Mask to determine the relevant bit of the crossing sum + // 0x1 if EVEN_ODD, all bits if NON_ZERO + int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0; + + // add 2 to better deal with the last pixel in a pixel row. + int width = inWidth; //ac.getWidth(); + int[] alpha = savedAlpha; + if ((alpha == null) || (savedAlphaSize < width+2)) { + alpha = new_int(width+2); + free(savedAlpha); + savedAlpha = alpha; + savedAlphaSize = width+2; + } else { + fill(alpha, 0, width+2, 0); + } + + int bboxx0 = inOrigin /*ac.getOriginX()*/ << SUBPIXEL_LG_POSITIONS_X; + int bboxx1 = bboxx0 + (width << SUBPIXEL_LG_POSITIONS_X); + + // Now we iterate through the scanlines. We must tell emitRow the coord + // of the first non-transparent pixel, so we must keep accumulators for + // the first and last pixels of the section of the current pixel row + // that we will emit. + // We also need to accumulate pix_bbox*, but the iterator does it + // for us. We will just get the values from it once this loop is done + int pix_maxX = bboxx1 >> SUBPIXEL_LG_POSITIONS_X; + int pix_minX = bboxx0 >> SUBPIXEL_LG_POSITIONS_Y; + + int y = boundsMinY; // needs to be declared here so we emit the last row properly. + if (sampleRowMin == 0) { + new_ScanlineIterator2(sampleRowMin, subpixelLgPositionsX, subpixelLgPositionsY); + } else { + /*it.*/reset(sampleRowMin); + } + for ( ; /*it.*/hasNext(sampleRowMax); ) { + int numCrossings = /*it.*/next(boundsMinY, edges, edgeBuckets); + //int[] crossings = it.crossings; + y = /*it.*/curY(); + + if (numCrossings > 0) { + int lowx = crossings[0] >> 1; + int highx = crossings[numCrossings - 1] >> 1; + int x0 = max(lowx, bboxx0); + int x1 = min(highx, bboxx1); + + pix_minX = min(pix_minX, x0 >> SUBPIXEL_LG_POSITIONS_X); + pix_maxX = max(pix_maxX, x1 >> SUBPIXEL_LG_POSITIONS_X); + } + + int sum = 0; + int prev = bboxx0; + for (int i = 0; i < numCrossings; i++) { + int curxo = crossings[i]; + int curx = curxo >> 1; + int crorientation = ((curxo & 0x1) << 1) - 1; + if ((sum & mask) != 0) { + int x0 = max(prev, bboxx0); + int x1 = min(curx, bboxx1); + if (x0 < x1) { + x0 -= bboxx0; // turn x0, x1 from coords to indices + x1 -= bboxx0; // in the alpha array. + + int pix_x = x0 >> SUBPIXEL_LG_POSITIONS_X; + int pix_xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X; + + if (pix_x == pix_xmaxm1) { + // Start and end in same pixel + alpha[pix_x] += (x1 - x0); + alpha[pix_x+1] -= (x1 - x0); + } else { + int pix_xmax = x1 >> SUBPIXEL_LG_POSITIONS_X; + alpha[pix_x] += SUBPIXEL_POSITIONS_X - (x0 & SUBPIXEL_MASK_X); + alpha[pix_x+1] += (x0 & SUBPIXEL_MASK_X); + alpha[pix_xmax] -= SUBPIXEL_POSITIONS_X - (x1 & SUBPIXEL_MASK_X); + alpha[pix_xmax+1] -= (x1 & SUBPIXEL_MASK_X); + } + } + } + sum += crorientation; + prev = curx; + } + + // even if this last row had no crossings, alpha will be zeroed + // from the last emitRow call. But this doesn't matter because + // maxX < minX, so no row will be emitted to the cache. + if ((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) { + setAndClearRelativeAlphas(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, + pix_minX, pix_maxX, alphas, alphaMap, inWidth, inY); + pix_maxX = bboxx1 >> SUBPIXEL_LG_POSITIONS_X; + pix_minX = bboxx0 >> SUBPIXEL_LG_POSITIONS_Y; + } + } + + // Emit final row. + // Note, if y is on a MASK row then it was already sent above... + if ((y & SUBPIXEL_MASK_Y) < SUBPIXEL_MASK_Y) { + setAndClearRelativeAlphas(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, + pix_minX, pix_maxX, alphas, alphaMap, inWidth, inY); + } +} + } diff -r a92ec8090ae5 prism-common/src/com/sun/prism/impl/shape/OpenPiscesRasterizer.java --- a/prism-common/src/com/sun/prism/impl/shape/OpenPiscesRasterizer.java Thu May 31 11:37:22 2012 -0400 +++ b/prism-common/src/com/sun/prism/impl/shape/OpenPiscesRasterizer.java Mon Jun 11 13:47:09 2012 -0400 @@ -22,6 +22,9 @@ private static Consumer savedConsumer; + static long Time; + static int Count; + @Override public MaskData getMaskData(Shape shape, BasicStroke stroke, @@ -81,7 +84,22 @@ } } consumer.setBoundsNoClone(outpix_xmin, outpix_ymin, w, h); - renderer.produceAlphas(consumer); + + long t0 = System.currentTimeMillis(); + if (System.getProperty("NATIVE_ALPHA") != null) { + renderer.init(consumer); + renderer.produceAlphas2(consumer, consumer.alphas, consumer.alphaMap, consumer.width, consumer.y); + } else { + renderer.produceAlphas(consumer); + } + Time += System.currentTimeMillis() - t0; + if (Count++ % 100 == 0) { + if (Count == 1) { + System.out.println("NATIVE_ALPHA: " + (System.getProperty("NATIVE_ALPHA") != null)); + } + System.out.println("Count=" + Count + ", Time=" + Time); + } + return consumer.getMaskData(); }