< prev index next >
openjfx9/modules/javafx.graphics/src/main/java/com/sun/marlin/Renderer.java
Print this page
*** 21,70 ****
* 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.
*/
! package sun.java2d.marlin;
! import java.util.Arrays;
! import sun.awt.geom.PathConsumer2D;
! import static sun.java2d.marlin.OffHeapArray.SIZE_INT;
import jdk.internal.misc.Unsafe;
! final class Renderer implements PathConsumer2D, MarlinConst {
static final boolean DISABLE_RENDER = false;
- static final boolean ENABLE_BLOCK_FLAGS = MarlinProperties.isUseTileFlags();
- static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics();
-
private static final int ALL_BUT_LSB = 0xfffffffe;
private static final int ERR_STEP_MAX = 0x7fffffff; // = 2^31 - 1
private static final double POWER_2_TO_32 = 0x1.0p32;
// use float to make tosubpix methods faster (no int to float conversion)
! public static final float F_SUBPIXEL_POSITIONS_X
= (float) SUBPIXEL_POSITIONS_X;
! public static final float F_SUBPIXEL_POSITIONS_Y
= (float) SUBPIXEL_POSITIONS_Y;
! public static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
! public static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
!
! // number of subpixels corresponding to a tile line
! private static final int SUBPIXEL_TILE
! = TILE_SIZE << SUBPIXEL_LG_POSITIONS_Y;
// 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
static final int INITIAL_BUCKET_ARRAY
= INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y;
! // crossing capacity = edges count / 8 ~ 512
! static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 3;
!
! public static final int WIND_EVEN_ODD = 0;
! public static final int WIND_NON_ZERO = 1;
// common to all types of input path segments.
// OFFSET as bytes
// only integer values:
public static final long OFF_CURX_OR = 0;
--- 21,58 ----
* 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.
*/
! package com.sun.marlin;
! import static com.sun.marlin.OffHeapArray.SIZE_INT;
import jdk.internal.misc.Unsafe;
! public final class Renderer implements MarlinRenderer, MarlinConst {
static final boolean DISABLE_RENDER = false;
private static final int ALL_BUT_LSB = 0xfffffffe;
private static final int ERR_STEP_MAX = 0x7fffffff; // = 2^31 - 1
private static final double POWER_2_TO_32 = 0x1.0p32;
// use float to make tosubpix methods faster (no int to float conversion)
! static final float F_SUBPIXEL_POSITIONS_X
= (float) SUBPIXEL_POSITIONS_X;
! static final float F_SUBPIXEL_POSITIONS_Y
= (float) SUBPIXEL_POSITIONS_Y;
! static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
! static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
// 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
static final int INITIAL_BUCKET_ARRAY
= INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y;
! // crossing capacity = edges count / 4 ~ 1024
! static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 2;
// common to all types of input path segments.
// OFFSET as bytes
// only integer values:
public static final long OFF_CURX_OR = 0;
*** 78,101 ****
public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
// curve break into lines
// cubic error in subpixels to decrement step
private static final float CUB_DEC_ERR_SUBPIX
! = 2.5f * (NORM_SUBPIXELS / 8f); // 2.5 subpixel for typical 8x8 subpixels
// cubic error in subpixels to increment step
private static final float CUB_INC_ERR_SUBPIX
! = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
// cubic bind length to decrement step = 8 * error in subpixels
- // pisces: 20 / 8
- // openjfx pisces: 8 / 3.2
// multiply by 8 = error scale factor:
public static final float CUB_DEC_BND
! = 8f * CUB_DEC_ERR_SUBPIX; // 20f means 2.5 subpixel error
// cubic bind length to increment step = 8 * error in subpixels
public static final float CUB_INC_BND
! = 8f * CUB_INC_ERR_SUBPIX; // 8f means 1 subpixel error
// cubic countlg
public static final int CUB_COUNT_LG = 2;
// cubic count = 2^countlg
private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
--- 66,87 ----
public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
// curve break into lines
// cubic error in subpixels to decrement step
private static final float CUB_DEC_ERR_SUBPIX
! = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
// cubic error in subpixels to increment step
private static final float CUB_INC_ERR_SUBPIX
! = 0.4f * (NORM_SUBPIXELS / 8f); // 0.4 subpixel for typical 8x8 subpixels
// cubic bind length to decrement step = 8 * error in subpixels
// multiply by 8 = error scale factor:
public static final float CUB_DEC_BND
! = 8f * CUB_DEC_ERR_SUBPIX;
// cubic bind length to increment step = 8 * error in subpixels
public static final float CUB_INC_BND
! = 8f * CUB_INC_ERR_SUBPIX;
// cubic countlg
public static final int CUB_COUNT_LG = 2;
// cubic count = 2^countlg
private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
*** 114,126 ****
// quadratic error in subpixels
private static final float QUAD_DEC_ERR_SUBPIX
= 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
// quadratic bind length to decrement step = 8 * error in subpixels
- // pisces and openjfx pisces: 32
public static final float QUAD_DEC_BND
! = 8f * QUAD_DEC_ERR_SUBPIX; // 8f means 1 subpixel error
//////////////////////////////////////////////////////////////////////////////
// SCAN LINE
//////////////////////////////////////////////////////////////////////////////
// crossings ie subpixel edge x coordinates
--- 100,111 ----
// quadratic error in subpixels
private static final float QUAD_DEC_ERR_SUBPIX
= 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
// quadratic bind length to decrement step = 8 * error in subpixels
public static final float QUAD_DEC_BND
! = 8f * QUAD_DEC_ERR_SUBPIX;
//////////////////////////////////////////////////////////////////////////////
// SCAN LINE
//////////////////////////////////////////////////////////////////////////////
// crossings ie subpixel edge x coordinates
*** 163,180 ****
private int[] edgeBuckets;
private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
// used range for edgeBuckets / edgeBucketCounts
private int buckets_minY;
private int buckets_maxY;
- // sum of each edge delta Y (subpixels)
- private int edgeSumDeltaY;
// edgeBuckets ref (clean)
private final IntArrayCache.Reference edgeBuckets_ref;
// edgeBucketCounts ref (clean)
private final IntArrayCache.Reference edgeBucketCounts_ref;
// Flattens using adaptive forward differencing. This only carries out
// one iteration of the AFD loop. All it does is update AFD variables (i.e.
// X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
private void quadBreakIntoLinesAndAdd(float x0, float y0,
final Curve c,
--- 148,165 ----
private int[] edgeBuckets;
private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
// used range for edgeBuckets / edgeBucketCounts
private int buckets_minY;
private int buckets_maxY;
// edgeBuckets ref (clean)
private final IntArrayCache.Reference edgeBuckets_ref;
// edgeBucketCounts ref (clean)
private final IntArrayCache.Reference edgeBucketCounts_ref;
+ boolean useRLE = false;
+
// Flattens using adaptive forward differencing. This only carries out
// one iteration of the AFD loop. All it does is update AFD variables (i.e.
// X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
private void quadBreakIntoLinesAndAdd(float x0, float y0,
final Curve c,
*** 482,494 ****
_edgeBuckets[bucketIdx] = edgePtr;
_edgeBucketCounts[bucketIdx] += 2; // 1 << 1
// last bit means edge end
_edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1;
- // update sum of delta Y (subpixels):
- edgeSumDeltaY += (lastCrossing - firstCrossing);
-
// update free pointer (ie length in bytes)
_edges.used += _SIZEOF_EDGE_BYTES;
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_addLine.stop();
--- 467,476 ----
*** 496,508 ****
}
// END EDGE LIST
//////////////////////////////////////////////////////////////////////////////
- // Cache to store RLE-encoded coverage mask of the current primitive
- final MarlinCache cache;
-
// Bounds of the drawing region, at subpixel precision.
private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
// Current winding rule
private int windingRule;
--- 478,487 ----
*** 548,559 ****
// 2048 (pixelsize) pixel large
alphaLine_ref = rdrCtx.newCleanIntArrayRef(INITIAL_AA_ARRAY); // 8K
alphaLine = alphaLine_ref.initial;
- this.cache = rdrCtx.cache;
-
crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
aux_crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
edgePtrs_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
aux_edgePtrs_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
--- 527,536 ----
*** 564,577 ****
blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
blkFlags = blkFlags_ref.initial;
}
! Renderer init(final int pix_boundsX, final int pix_boundsY,
final int pix_boundsWidth, final int pix_boundsHeight,
! final int windingRule) {
!
this.windingRule = windingRule;
// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
this.boundsMinX = pix_boundsX << SUBPIXEL_LG_POSITIONS_X;
this.boundsMaxX =
--- 541,554 ----
blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
blkFlags = blkFlags_ref.initial;
}
! public Renderer init(final int pix_boundsX, final int pix_boundsY,
final int pix_boundsWidth, final int pix_boundsHeight,
! final int windingRule)
! {
this.windingRule = windingRule;
// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
this.boundsMinX = pix_boundsX << SUBPIXEL_LG_POSITIONS_X;
this.boundsMaxX =
*** 609,627 ****
// reset used mark:
edgeCount = 0;
activeEdgeMaxUsed = 0;
edges.used = 0;
! edgeSumDeltaY = 0;
return this; // fluent API
}
/**
* Disposes this renderer and recycle it clean up before reusing this instance
*/
! void dispose() {
if (DO_STATS) {
rdrCtx.stats.stat_rdr_activeEdges.add(activeEdgeMaxUsed);
rdrCtx.stats.stat_rdr_edges.add(edges.used);
rdrCtx.stats.stat_rdr_edges_count.add(edges.used / SIZEOF_EDGE_BYTES);
rdrCtx.stats.hist_rdr_edges_count.add(edges.used / SIZEOF_EDGE_BYTES);
--- 586,606 ----
// reset used mark:
edgeCount = 0;
activeEdgeMaxUsed = 0;
edges.used = 0;
! // reset bbox:
! bboxX0 = 0;
! bboxX1 = 0;
return this; // fluent API
}
/**
* Disposes this renderer and recycle it clean up before reusing this instance
*/
! public void dispose() {
if (DO_STATS) {
rdrCtx.stats.stat_rdr_activeEdges.add(activeEdgeMaxUsed);
rdrCtx.stats.stat_rdr_edges.add(edges.used);
rdrCtx.stats.stat_rdr_edges_count.add(edges.used / SIZEOF_EDGE_BYTES);
rdrCtx.stats.hist_rdr_edges_count.add(edges.used / SIZEOF_EDGE_BYTES);
*** 732,749 ****
}
@Override
public void pathDone() {
closePath();
- }
! @Override
! public long getNativeConsumer() {
! throw new InternalError("Renderer does not use a native consumer.");
}
! private void _endRendering(final int ymin, final int ymax) {
if (DISABLE_RENDER) {
return;
}
// Get X bounds as true pixel boundaries to compute correct pixel coverage:
--- 711,728 ----
}
@Override
public void pathDone() {
closePath();
! // call endRendering() to determine the boundaries:
! endRendering();
}
! private void _endRendering(final int ymin, final int ymax,
! final MarlinAlphaConsumer ac)
! {
if (DISABLE_RENDER) {
return;
}
// Get X bounds as true pixel boundaries to compute correct pixel coverage:
*** 754,764 ****
// Useful when processing tile line by tile line
final int[] _alpha = alphaLine;
// local vars (performance):
- final MarlinCache _cache = cache;
final OffHeapArray _edges = edges;
final int[] _edgeBuckets = edgeBuckets;
final int[] _edgeBucketCounts = edgeBucketCounts;
int[] _crossings = this.crossings;
--- 733,742 ----
*** 1174,1184 ****
if ((sum & 0x1) != 0) {
// TODO: perform line clipping on left-right sides
// to avoid such bound checks:
x0 = (prev > bboxx0) ? prev : bboxx0;
! x1 = (curx < bboxx1) ? curx : bboxx1;
if (x0 < x1) {
x0 -= bboxx0; // turn x0, x1 from coords to indices
x1 -= bboxx0; // in the alpha array.
--- 1152,1169 ----
if ((sum & 0x1) != 0) {
// TODO: perform line clipping on left-right sides
// to avoid such bound checks:
x0 = (prev > bboxx0) ? prev : bboxx0;
!
! if (curx < bboxx1) {
! x1 = curx;
! } else {
! x1 = bboxx1;
! // skip right side (fast exit loop):
! i = numCrossings;
! }
if (x0 < x1) {
x0 -= bboxx0; // turn x0, x1 from coords to indices
x1 -= bboxx0; // in the alpha array.
*** 1191,1201 ****
_alpha[pix_x ] += tmp;
_alpha[pix_x + 1] -= tmp;
if (useBlkFlags) {
// flag used blocks:
! _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
}
} else {
tmp = (x0 & _SUBPIXEL_MASK_X);
_alpha[pix_x ]
+= (_SUBPIXEL_POSITIONS_X - tmp);
--- 1176,1187 ----
_alpha[pix_x ] += tmp;
_alpha[pix_x + 1] -= tmp;
if (useBlkFlags) {
// flag used blocks:
! _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
! _blkFlags[(pix_x + 1) >> _BLK_SIZE_LG] = 1;
}
} else {
tmp = (x0 & _SUBPIXEL_MASK_X);
_alpha[pix_x ]
+= (_SUBPIXEL_POSITIONS_X - tmp);
*** 1210,1221 ****
_alpha[pix_xmax + 1]
-= tmp;
if (useBlkFlags) {
// flag used blocks:
! _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
! _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
}
}
}
}
--- 1196,1209 ----
_alpha[pix_xmax + 1]
-= tmp;
if (useBlkFlags) {
// flag used blocks:
! _blkFlags[ pix_x >> _BLK_SIZE_LG] = 1;
! _blkFlags[(pix_x + 1) >> _BLK_SIZE_LG] = 1;
! _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
! _blkFlags[(pix_xmax + 1) >> _BLK_SIZE_LG] = 1;
}
}
}
}
*** 1235,1245 ****
}
} else {
// TODO: perform line clipping on left-right sides
// to avoid such bound checks:
x0 = (prev > bboxx0) ? prev : bboxx0;
! x1 = (curx < bboxx1) ? curx : bboxx1;
if (x0 < x1) {
x0 -= bboxx0; // turn x0, x1 from coords to indices
x1 -= bboxx0; // in the alpha array.
--- 1223,1240 ----
}
} else {
// TODO: perform line clipping on left-right sides
// to avoid such bound checks:
x0 = (prev > bboxx0) ? prev : bboxx0;
!
! if (curx < bboxx1) {
! x1 = curx;
! } else {
! x1 = bboxx1;
! // skip right side (fast exit loop):
! i = numCrossings;
! }
if (x0 < x1) {
x0 -= bboxx0; // turn x0, x1 from coords to indices
x1 -= bboxx0; // in the alpha array.
*** 1252,1262 ****
_alpha[pix_x ] += tmp;
_alpha[pix_x + 1] -= tmp;
if (useBlkFlags) {
// flag used blocks:
! _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
}
} else {
tmp = (x0 & _SUBPIXEL_MASK_X);
_alpha[pix_x ]
+= (_SUBPIXEL_POSITIONS_X - tmp);
--- 1247,1258 ----
_alpha[pix_x ] += tmp;
_alpha[pix_x + 1] -= tmp;
if (useBlkFlags) {
// flag used blocks:
! _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
! _blkFlags[(pix_x + 1) >> _BLK_SIZE_LG] = 1;
}
} else {
tmp = (x0 & _SUBPIXEL_MASK_X);
_alpha[pix_x ]
+= (_SUBPIXEL_POSITIONS_X - tmp);
*** 1271,1282 ****
_alpha[pix_xmax + 1]
-= tmp;
if (useBlkFlags) {
// flag used blocks:
! _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
! _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
}
}
}
prev = _MAX_VALUE;
}
--- 1267,1280 ----
_alpha[pix_xmax + 1]
-= tmp;
if (useBlkFlags) {
// flag used blocks:
! _blkFlags[ pix_x >> _BLK_SIZE_LG] = 1;
! _blkFlags[(pix_x + 1) >> _BLK_SIZE_LG] = 1;
! _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
! _blkFlags[(pix_xmax + 1) >> _BLK_SIZE_LG] = 1;
}
}
}
prev = _MAX_VALUE;
}
*** 1294,1316 ****
}
} // numCrossings > 0
// 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 MarlinCache.
if ((y & _SUBPIXEL_MASK_Y) == _SUBPIXEL_MASK_Y) {
lastY = y >> _SUBPIXEL_LG_POSITIONS_Y;
// convert subpixel to pixel coordinate within boundaries:
minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
if (maxX >= minX) {
// note: alpha array will be zeroed by copyAARow()
! // +2 because alpha [pix_minX; pix_maxX+1]
// fix range [x0; x1[
! copyAARow(_alpha, lastY, minX, maxX + 2, useBlkFlags);
// speculative for next pixel row (scanline coherence):
if (_enableBlkFlagsHeuristics) {
// Use block flags if large pixel span and few crossings:
// ie mean(distance between crossings) is larger than
--- 1292,1317 ----
}
} // numCrossings > 0
// 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 AlphaConsumer.
if ((y & _SUBPIXEL_MASK_Y) == _SUBPIXEL_MASK_Y) {
lastY = y >> _SUBPIXEL_LG_POSITIONS_Y;
// convert subpixel to pixel coordinate within boundaries:
minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
if (maxX >= minX) {
// note: alpha array will be zeroed by copyAARow()
! // +1 because alpha [pix_minX; pix_maxX[
// fix range [x0; x1[
! // note: if x1=bboxx1, then alpha is written up to bboxx1+1
! // inclusive: alpha[bboxx1] ignored, alpha[bboxx1+1] == 0
! // (normally so never cleared below)
! copyAARow(_alpha, lastY, minX, maxX + 1, useBlkFlags, ac);
// speculative for next pixel row (scanline coherence):
if (_enableBlkFlagsHeuristics) {
// Use block flags if large pixel span and few crossings:
// ie mean(distance between crossings) is larger than
*** 1331,1341 ****
rdrCtx.stats.hist_tile_generator_encoding_dist
.add(maxX / tmp);
}
}
} else {
! _cache.clearAARow(lastY);
}
minX = _MAX_VALUE;
maxX = _MIN_VALUE;
}
} // scan line iterator
--- 1332,1342 ----
rdrCtx.stats.hist_tile_generator_encoding_dist
.add(maxX / tmp);
}
}
} else {
! ac.clearAlphas(lastY);
}
minX = _MAX_VALUE;
maxX = _MIN_VALUE;
}
} // scan line iterator
*** 1348,1362 ****
minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
if (maxX >= minX) {
// note: alpha array will be zeroed by copyAARow()
! // +2 because alpha [pix_minX; pix_maxX+1]
// fix range [x0; x1[
! copyAARow(_alpha, y, minX, maxX + 2, useBlkFlags);
} else if (y != lastY) {
! _cache.clearAARow(y);
}
// update member:
edgeCount = numCrossings;
prevUseBlkFlags = useBlkFlags;
--- 1349,1366 ----
minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
if (maxX >= minX) {
// note: alpha array will be zeroed by copyAARow()
! // +1 because alpha [pix_minX; pix_maxX[
// fix range [x0; x1[
! // note: if x1=bboxx1, then alpha is written up to bboxx1+1
! // inclusive: alpha[bboxx1] ignored then cleared and
! // alpha[bboxx1+1] == 0 (normally so never cleared after)
! copyAARow(_alpha, y, minX, maxX + 1, useBlkFlags, ac);
} else if (y != lastY) {
! ac.clearAlphas(y);
}
// update member:
edgeCount = numCrossings;
prevUseBlkFlags = useBlkFlags;
*** 1365,1380 ****
// update max used mark
activeEdgeMaxUsed = _arrayMaxUsed;
}
}
! boolean endRendering() {
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering.start();
}
if (edgeMinY == Integer.MAX_VALUE) {
! return false; // undefined edges bounds
}
final int _boundsMinY = boundsMinY;
final int _boundsMaxY = boundsMaxY;
--- 1369,1384 ----
// update max used mark
activeEdgeMaxUsed = _arrayMaxUsed;
}
}
! void endRendering() {
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering.start();
}
if (edgeMinY == Integer.MAX_VALUE) {
! return; // undefined edges bounds
}
final int _boundsMinY = boundsMinY;
final int _boundsMaxY = boundsMaxY;
*** 1403,1413 ****
+ "][" + spminY + " ... " + spmaxY + "]");
}
// test clipping for shapes out of bounds
if ((spminX > spmaxX) || (spminY > spmaxY)) {
! return false;
}
// half open intervals
// inclusive:
final int pminX = spminX >> SUBPIXEL_LG_POSITIONS_X;
--- 1407,1417 ----
+ "][" + spminY + " ... " + spmaxY + "]");
}
// test clipping for shapes out of bounds
if ((spminX > spmaxX) || (spminY > spmaxY)) {
! return;
}
// half open intervals
// inclusive:
final int pminX = spminX >> SUBPIXEL_LG_POSITIONS_X;
*** 1417,1439 ****
final int pminY = spminY >> SUBPIXEL_LG_POSITIONS_Y;
// exclusive:
final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
// store BBox to answer ptg.getBBox():
! this.cache.init(pminX, pminY, pmaxX, pmaxY, edgeSumDeltaY);
// Heuristics for using block flags:
if (ENABLE_BLOCK_FLAGS) {
! enableBlkFlags = this.cache.useRLE;
prevUseBlkFlags = enableBlkFlags && !ENABLE_BLOCK_FLAGS_HEURISTICS;
if (enableBlkFlags) {
// ensure blockFlags array is large enough:
// note: +2 to ensure enough space left at end
! final int nxTiles = ((pmaxX - pminX) >> TILE_SIZE_LG) + 2;
! if (nxTiles > INITIAL_ARRAY) {
! blkFlags = blkFlags_ref.getArray(nxTiles);
}
}
}
// memorize the rendering bounding box:
--- 1421,1443 ----
final int pminY = spminY >> SUBPIXEL_LG_POSITIONS_Y;
// exclusive:
final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
// store BBox to answer ptg.getBBox():
! initConsumer(pminX, pminY, pmaxX, pmaxY);
// Heuristics for using block flags:
if (ENABLE_BLOCK_FLAGS) {
! enableBlkFlags = this.useRLE;
prevUseBlkFlags = enableBlkFlags && !ENABLE_BLOCK_FLAGS_HEURISTICS;
if (enableBlkFlags) {
// ensure blockFlags array is large enough:
// note: +2 to ensure enough space left at end
! final int blkLen = ((pmaxX - pminX) >> BLOCK_SIZE_LG) + 2;
! if (blkLen > INITIAL_ARRAY) {
! blkFlags = blkFlags_ref.getArray(blkLen);
}
}
}
// memorize the rendering bounding box:
*** 1465,1519 ****
if (DO_STATS) {
rdrCtx.stats.stat_array_renderer_alphaline.add(width);
}
alphaLine = alphaLine_ref.getArray(width);
}
! // process first tile line:
! endRendering(pminY);
! return true;
}
private int bbox_spminX, bbox_spmaxX, bbox_spminY, bbox_spmaxY;
! void endRendering(final int pminY) {
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering_Y.start();
}
! final int spminY = pminY << SUBPIXEL_LG_POSITIONS_Y;
! final int fixed_spminY = FloatMath.max(bbox_spminY, spminY);
!
! // avoid rendering for last call to nextTile()
! if (fixed_spminY < bbox_spmaxY) {
! // process a complete tile line ie scanlines for 32 rows
! final int spmaxY = FloatMath.min(bbox_spmaxY, spminY + SUBPIXEL_TILE);
- // process tile line [0 - 32]
- cache.resetTileLine(pminY);
-
- // Process only one tile line:
- _endRendering(fixed_spminY, spmaxY);
- }
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering_Y.stop();
}
}
void copyAARow(final int[] alphaRow,
final int pix_y, final int pix_from, final int pix_to,
! final boolean useBlockFlags)
{
if (useBlockFlags) {
if (DO_STATS) {
rdrCtx.stats.hist_tile_generator_encoding.add(1);
}
! cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to);
} else {
if (DO_STATS) {
rdrCtx.stats.hist_tile_generator_encoding.add(0);
}
! cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
}
}
}
--- 1469,1576 ----
if (DO_STATS) {
rdrCtx.stats.stat_array_renderer_alphaline.add(width);
}
alphaLine = alphaLine_ref.getArray(width);
}
+ }
! void initConsumer(int minx, int miny, int maxx, int maxy)
! {
! // assert maxy >= miny && maxx >= minx;
! bboxX0 = minx;
! bboxX1 = maxx;
! bboxY0 = miny;
! bboxY1 = maxy;
!
! final int width = (maxx - minx);
!
! if (FORCE_NO_RLE) {
! useRLE = false;
! } else if (FORCE_RLE) {
! useRLE = true;
! } else {
! // heuristics: use both bbox area and complexity
! // ie number of primitives:
! // fast check min width:
! if (width <= RLE_MIN_WIDTH) {
! useRLE = false;
! } else {
! useRLE = true;
! }
! }
}
private int bbox_spminX, bbox_spmaxX, bbox_spminY, bbox_spmaxY;
! public void produceAlphas(final MarlinAlphaConsumer ac) {
! ac.setMaxAlpha(MAX_AA_ALPHA);
!
! if (enableBlkFlags && !ac.supportBlockFlags()) {
! // consumer does not support block flag optimization:
! enableBlkFlags = false;
! prevUseBlkFlags = false;
! }
!
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering_Y.start();
}
! // Process all scan lines:
! _endRendering(bbox_spminY, bbox_spmaxY, ac);
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering_Y.stop();
}
}
void copyAARow(final int[] alphaRow,
final int pix_y, final int pix_from, final int pix_to,
! final boolean useBlockFlags,
! final MarlinAlphaConsumer ac)
{
+ if (DO_MONITORS) {
+ rdrCtx.stats.mon_rdr_copyAARow.start();
+ }
+ if (DO_STATS) {
+ rdrCtx.stats.stat_cache_rowAA.add(pix_to - pix_from);
+ }
+
if (useBlockFlags) {
if (DO_STATS) {
rdrCtx.stats.hist_tile_generator_encoding.add(1);
}
! ac.setAndClearRelativeAlphas(blkFlags, alphaRow, pix_y, pix_from, pix_to);
} else {
if (DO_STATS) {
rdrCtx.stats.hist_tile_generator_encoding.add(0);
}
! ac.setAndClearRelativeAlphas(alphaRow, pix_y, pix_from, pix_to);
! }
! if (DO_MONITORS) {
! rdrCtx.stats.mon_rdr_copyAARow.stop();
}
}
+
+ // output pixel bounding box:
+ int bboxX0, bboxX1, bboxY0, bboxY1;
+
+ @Override
+ public int getOutpixMinX() {
+ return bboxX0;
+ }
+
+ @Override
+ public int getOutpixMaxX() {
+ return bboxX1;
+ }
+
+ @Override
+ public int getOutpixMinY() {
+ return bboxY0;
+ }
+
+ @Override
+ public int getOutpixMaxY() {
+ return bboxY1;
+ }
}
< prev index next >