< prev index next >
src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2007, 2016, 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. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2007, 2017, 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. Oracle designates this
*** 23,67 ****
* 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.
--- 23,64 ----
* questions.
*/
package sun.java2d.marlin;
import sun.awt.geom.PathConsumer2D;
import static sun.java2d.marlin.OffHeapArray.SIZE_INT;
import jdk.internal.misc.Unsafe;
! final class Renderer implements PathConsumer2D, MarlinRenderer {
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.0p32d;
// use float to make tosubpix methods faster (no int to float conversion)
! static final float SUBPIXEL_SCALE_X = (float) SUBPIXEL_POSITIONS_X;
! static final float SUBPIXEL_SCALE_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;
// number of subpixels corresponding to a tile line
private static final int SUBPIXEL_TILE
! = TILE_H << 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 / 4 ~ 1024
! static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 2;
public static final int WIND_EVEN_ODD = 0;
public static final int WIND_NON_ZERO = 1;
// common to all types of input path segments.
*** 78,126 ****
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;
// cubic count^2 = 4^countlg
private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
// cubic count^3 = 8^countlg
private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
// cubic dt = 1 / count
! private static final float CUB_INV_COUNT = 1f / CUB_COUNT;
// cubic dt^2 = 1 / count^2 = 1 / 4^countlg
! private static final float CUB_INV_COUNT_2 = 1f / CUB_COUNT_2;
// cubic dt^3 = 1 / count^3 = 1 / 8^countlg
! private static final float CUB_INV_COUNT_3 = 1f / CUB_COUNT_3;
// quad break into lines
// 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
--- 75,125 ----
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
! = MarlinProperties.getCubicDecD2() * (NORM_SUBPIXELS / 8.0f); // 1 pixel
// cubic error in subpixels to increment step
private static final float CUB_INC_ERR_SUBPIX
! = MarlinProperties.getCubicIncD1() * (NORM_SUBPIXELS / 8.0f); // 0.4 pixel
! // TestNonAARasterization (JDK-8170879): cubics
! // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07)
!
! // cubic bind length to decrement step
public static final float CUB_DEC_BND
! = 8.0f * CUB_DEC_ERR_SUBPIX;
! // cubic bind length to increment step
public static final float CUB_INC_BND
! = 8.0f * 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;
// cubic count^2 = 4^countlg
private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
// cubic count^3 = 8^countlg
private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
// cubic dt = 1 / count
! private static final float CUB_INV_COUNT = 1.0f / CUB_COUNT;
// cubic dt^2 = 1 / count^2 = 1 / 4^countlg
! private static final float CUB_INV_COUNT_2 = 1.0f / CUB_COUNT_2;
// cubic dt^3 = 1 / count^3 = 1 / 8^countlg
! private static final float CUB_INV_COUNT_3 = 1.0f / CUB_COUNT_3;
// quad break into lines
// quadratic error in subpixels
private static final float QUAD_DEC_ERR_SUBPIX
! = MarlinProperties.getQuadDecD2() * (NORM_SUBPIXELS / 8.0f); // 0.5 pixel
!
! // TestNonAARasterization (JDK-8170879): quads
! // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10)
! // quadratic bind length to decrement step
public static final float QUAD_DEC_BND
! = 8.0f * QUAD_DEC_ERR_SUBPIX;
//////////////////////////////////////////////////////////////////////////////
// SCAN LINE
//////////////////////////////////////////////////////////////////////////////
// crossings ie subpixel edge x coordinates
*** 155,174 ****
private int edgeMinY = Integer.MAX_VALUE;
private int edgeMaxY = Integer.MIN_VALUE;
private float edgeMinX = Float.POSITIVE_INFINITY;
private float edgeMaxX = Float.NEGATIVE_INFINITY;
! // edges [floats|ints] stored in off-heap memory
private final OffHeapArray edges;
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;
--- 154,171 ----
private int edgeMinY = Integer.MAX_VALUE;
private int edgeMaxY = Integer.MIN_VALUE;
private float edgeMinX = Float.POSITIVE_INFINITY;
private float edgeMaxX = Float.NEGATIVE_INFINITY;
! // edges [ints] stored in off-heap memory
private final OffHeapArray edges;
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;
*** 181,207 ****
final float x2, final float y2)
{
int count = 1; // dt = 1 / count
// maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
! float maxDD = FloatMath.max(Math.abs(c.dbx), Math.abs(c.dby));
final float _DEC_BND = QUAD_DEC_BND;
while (maxDD >= _DEC_BND) {
// divide step by half:
! maxDD /= 4f; // error divided by 2^2 = 4
count <<= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
}
}
int nL = 0; // line count
if (count > 1) {
! final float icount = 1f / count; // dt
final float icount2 = icount * icount; // dt^2
final float ddx = c.dbx * icount2;
final float ddy = c.dby * icount2;
float dx = c.bx * icount2 + c.cx * icount;
--- 178,204 ----
final float x2, final float y2)
{
int count = 1; // dt = 1 / count
// maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
! float maxDD = Math.abs(c.dbx) + Math.abs(c.dby);
final float _DEC_BND = QUAD_DEC_BND;
while (maxDD >= _DEC_BND) {
// divide step by half:
! maxDD /= 4.0f; // error divided by 2^2 = 4
count <<= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
}
}
int nL = 0; // line count
if (count > 1) {
! final float icount = 1.0f / count; // dt
final float icount2 = icount * icount; // dt^2
final float ddx = c.dbx * icount2;
final float ddy = c.dby * icount2;
float dx = c.bx * icount2 + c.cx * icount;
*** 244,255 ****
final float icount3 = CUB_INV_COUNT_3; // dt^3
// the dx and dy refer to forward differencing variables, not the last
// coefficients of the "points" polynomial
float dddx, dddy, ddx, ddy, dx, dy;
! dddx = 2f * c.dax * icount3;
! dddy = 2f * c.day * icount3;
ddx = dddx + c.dbx * icount2;
ddy = dddy + c.dby * icount2;
dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
--- 241,252 ----
final float icount3 = CUB_INV_COUNT_3; // dt^3
// the dx and dy refer to forward differencing variables, not the last
// coefficients of the "points" polynomial
float dddx, dddy, ddx, ddy, dx, dy;
! dddx = 2.0f * c.dax * icount3;
! dddy = 2.0f * c.day * icount3;
ddx = dddx + c.dbx * icount2;
ddy = dddy + c.dby * icount2;
dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
*** 260,297 ****
final float _DEC_BND = CUB_DEC_BND;
final float _INC_BND = CUB_INC_BND;
while (count > 0) {
// divide step by half:
! while (Math.abs(ddx) >= _DEC_BND || Math.abs(ddy) >= _DEC_BND) {
! dddx /= 8f;
! dddy /= 8f;
! ddx = ddx/4f - dddx;
! ddy = ddy/4f - dddy;
! dx = (dx - ddx) / 2f;
! dy = (dy - ddy) / 2f;
count <<= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
}
}
// double step:
- // TODO: why use first derivative dX|Y instead of second ddX|Y ?
- // both scale changes should use speed or acceleration to have the same metric.
-
// can only do this on even "count" values, because we must divide count by 2
while (count % 2 == 0
! && Math.abs(dx) <= _INC_BND && Math.abs(dy) <= _INC_BND)
{
! dx = 2f * dx + ddx;
! dy = 2f * dy + ddy;
! ddx = 4f * (ddx + dddx);
! ddy = 4f * (ddy + dddy);
! dddx *= 8f;
! dddy *= 8f;
count >>= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
}
--- 257,291 ----
final float _DEC_BND = CUB_DEC_BND;
final float _INC_BND = CUB_INC_BND;
while (count > 0) {
// divide step by half:
! while (Math.abs(ddx) + Math.abs(ddy) >= _DEC_BND) {
! dddx /= 8.0f;
! dddy /= 8.0f;
! ddx = ddx / 4.0f - dddx;
! ddy = ddy / 4.0f - dddy;
! dx = (dx - ddx) / 2.0f;
! dy = (dy - ddy) / 2.0f;
count <<= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
}
}
// double step:
// can only do this on even "count" values, because we must divide count by 2
while (count % 2 == 0
! && Math.abs(dx) + Math.abs(dy) <= _INC_BND)
{
! dx = 2.0f * dx + ddx;
! dy = 2.0f * dy + ddy;
! ddx = 4.0f * (ddx + dddx);
! ddy = 4.0f * (ddy + dddy);
! dddx *= 8.0f;
! dddy *= 8.0f;
count >>= 1;
if (DO_STATS) {
rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
}
*** 335,345 ****
tmp = x2;
x2 = x1;
x1 = tmp;
}
! // convert subpixel coordinates (float) into pixel positions (int)
// The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
// Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
// ceil(y1) or ceil(y2)
// upper integer (inclusive)
--- 329,339 ----
tmp = x2;
x2 = x1;
x1 = tmp;
}
! // convert subpixel coordinates [float] into pixel positions [int]
// The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
// Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
// ceil(y1) or ceil(y2)
// upper integer (inclusive)
*** 359,369 ****
rdrCtx.stats.stat_rdr_addLine_skip.add(1);
}
return;
}
! // edge min/max X/Y are in subpixel space (inclusive) within bounds:
// note: Use integer crossings to ensure consistent range within
// edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0)
if (firstCrossing < edgeMinY) {
edgeMinY = firstCrossing;
}
--- 353,363 ----
rdrCtx.stats.stat_rdr_addLine_skip.add(1);
}
return;
}
! // edge min/max X/Y are in subpixel space (half-open interval):
// note: Use integer crossings to ensure consistent range within
// edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0)
if (firstCrossing < edgeMinY) {
edgeMinY = firstCrossing;
}
*** 374,384 ****
// Use double-precision for improved accuracy:
final double x1d = x1;
final double y1d = y1;
final double slope = (x1d - x2) / (y1d - y2);
! if (slope >= 0.0) { // <==> x1 < x2
if (x1 < edgeMinX) {
edgeMinX = x1;
}
if (x2 > edgeMaxX) {
edgeMaxX = x2;
--- 368,378 ----
// Use double-precision for improved accuracy:
final double x1d = x1;
final double y1d = y1;
final double slope = (x1d - x2) / (y1d - y2);
! if (slope >= 0.0d) { // <==> x1 < x2
if (x1 < edgeMinX) {
edgeMinX = x1;
}
if (x2 > edgeMaxX) {
edgeMaxX = x2;
*** 437,453 ****
// epsilon is hard to pin down in floating point, but easy in fixed point, so if
// we convert to fixed point then these operations get easier:
// long x1_fixed = x1_intercept * 2^32; (fixed point 32.32 format)
// curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
// = fixed_floor(x1_fixed + 2^31 - 1)
! // = fixed_floor(x1_fixed + 0x7fffffff)
! // and error = fixed_fract(x1_fixed + 0x7fffffff)
final double x1_intercept = x1d + (firstCrossing - y1d) * slope;
// inlined scalb(x1_intercept, 32):
final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
! + 0x7fffffffL;
// curx:
// last bit corresponds to the orientation
_unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
addr += SIZE_INT;
_unsafe.putInt(addr, ((int) x1_fixed_biased) >>> 1);
--- 431,447 ----
// epsilon is hard to pin down in floating point, but easy in fixed point, so if
// we convert to fixed point then these operations get easier:
// long x1_fixed = x1_intercept * 2^32; (fixed point 32.32 format)
// curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
// = fixed_floor(x1_fixed + 2^31 - 1)
! // = fixed_floor(x1_fixed + 0x7FFFFFFF)
! // and error = fixed_fract(x1_fixed + 0x7FFFFFFF)
final double x1_intercept = x1d + (firstCrossing - y1d) * slope;
// inlined scalb(x1_intercept, 32):
final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
! + 0x7FFFFFFFL;
// curx:
// last bit corresponds to the orientation
_unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
addr += SIZE_INT;
_unsafe.putInt(addr, ((int) x1_fixed_biased) >>> 1);
*** 472,494 ****
final int bucketIdx = firstCrossing - _boundsMinY;
// pointer from bucket
_unsafe.putInt(addr, _edgeBuckets[bucketIdx]);
addr += SIZE_INT;
! // y max (inclusive)
_unsafe.putInt(addr, lastCrossing);
// Update buckets:
// directly the edge struct "pointer"
_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();
--- 466,485 ----
final int bucketIdx = firstCrossing - _boundsMinY;
// pointer from bucket
_unsafe.putInt(addr, _edgeBuckets[bucketIdx]);
addr += SIZE_INT;
! // y max (exclusive)
_unsafe.putInt(addr, lastCrossing);
// Update buckets:
// directly the edge struct "pointer"
_edgeBuckets[bucketIdx] = edgePtr;
_edgeBucketCounts[bucketIdx] += 2; // 1 << 1
// last bit means edge end
_edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1;
// update free pointer (ie length in bytes)
_edges.used += _SIZEOF_EDGE_BYTES;
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_addLine.stop();
*** 566,577 ****
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 =
--- 557,568 ----
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 =
*** 609,620 ****
// 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
--- 600,609 ----
*** 667,685 ****
edges.fill(BYTE_0);
}
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering.stop();
}
}
private static float tosubpixx(final float pix_x) {
! return F_SUBPIXEL_POSITIONS_X * pix_x;
}
private static float tosubpixy(final float pix_y) {
// shift y by -0.5 for fast ceil(y - 0.5):
! return F_SUBPIXEL_POSITIONS_Y * pix_y - 0.5f;
}
@Override
public void moveTo(float pix_x0, float pix_y0) {
closePath();
--- 656,676 ----
edges.fill(BYTE_0);
}
if (DO_MONITORS) {
rdrCtx.stats.mon_rdr_endRendering.stop();
}
+ // recycle the RendererContext instance
+ MarlinRenderingEngine.returnRendererContext(rdrCtx);
}
private static float tosubpixx(final float pix_x) {
! return SUBPIXEL_SCALE_X * pix_x;
}
private static float tosubpixy(final float pix_y) {
// shift y by -0.5 for fast ceil(y - 0.5):
! return SUBPIXEL_SCALE_Y * pix_y - 0.5f;
}
@Override
public void moveTo(float pix_x0, float pix_y0) {
closePath();
*** 700,711 ****
y0 = y1;
}
@Override
public void curveTo(float x1, float y1,
! float x2, float y2,
! float x3, float y3)
{
final float xe = tosubpixx(x3);
final float ye = tosubpixy(y3);
curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1),
tosubpixx(x2), tosubpixy(y2), xe, ye);
--- 691,702 ----
y0 = y1;
}
@Override
public void curveTo(float x1, float y1,
! float x2, float y2,
! float x3, float y3)
{
final float xe = tosubpixx(x3);
final float ye = tosubpixy(y3);
curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1),
tosubpixx(x2), tosubpixy(y2), xe, ye);
*** 967,978 ****
for (i = 0; i < numCrossings; i++) {
// get the pointer to the edge
ecur = _edgePtrs[i];
! /* convert subpixel coordinates (float) into pixel
! positions (int) for coming scanline */
/* note: it is faster to always update edges even
if it is removed from AEL for coming or last scanline */
// random access so use unsafe:
addr = addr0 + ecur; // ecur + OFF_F_CURX
--- 958,969 ----
for (i = 0; i < numCrossings; i++) {
// get the pointer to the edge
ecur = _edgePtrs[i];
! /* convert subpixel coordinates into pixel
! positions for coming scanline */
/* note: it is faster to always update edges even
if it is removed from AEL for coming or last scanline */
// random access so use unsafe:
addr = addr0 + ecur; // ecur + OFF_F_CURX
*** 1067,1078 ****
for (i = 0; i < numCrossings; i++) {
// get the pointer to the edge
ecur = _edgePtrs[i];
! /* convert subpixel coordinates (float) into pixel
! positions (int) for coming scanline */
/* note: it is faster to always update edges even
if it is removed from AEL for coming or last scanline */
// random access so use unsafe:
addr = addr0 + ecur; // ecur + OFF_F_CURX
--- 1058,1069 ----
for (i = 0; i < numCrossings; i++) {
// get the pointer to the edge
ecur = _edgePtrs[i];
! /* convert subpixel coordinates into pixel
! positions for coming scanline */
/* note: it is faster to always update edges even
if it is removed from AEL for coming or last scanline */
// random access so use unsafe:
addr = addr0 + ecur; // ecur + OFF_F_CURX
*** 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.
--- 1165,1182 ----
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);
--- 1189,1200 ----
_alpha[pix_x ] += tmp;
_alpha[pix_x + 1] -= tmp;
if (useBlkFlags) {
// flag used blocks:
! // note: block processing handles extra pixel:
! _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
}
} else {
tmp = (x0 & _SUBPIXEL_MASK_X);
_alpha[pix_x ]
+= (_SUBPIXEL_POSITIONS_X - tmp);
*** 1210,1219 ****
--- 1209,1219 ----
_alpha[pix_xmax + 1]
-= tmp;
if (useBlkFlags) {
// flag used blocks:
+ // note: block processing handles extra pixel:
_blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
_blkFlags[pix_xmax >> _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.
--- 1235,1252 ----
}
} 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);
--- 1259,1270 ----
_alpha[pix_x ] += tmp;
_alpha[pix_x + 1] -= tmp;
if (useBlkFlags) {
// flag used blocks:
! // note: block processing handles extra pixel:
! _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
}
} else {
tmp = (x0 & _SUBPIXEL_MASK_X);
_alpha[pix_x ]
+= (_SUBPIXEL_POSITIONS_X - tmp);
*** 1271,1280 ****
--- 1279,1289 ----
_alpha[pix_xmax + 1]
-= tmp;
if (useBlkFlags) {
// flag used blocks:
+ // note: block processing handles extra pixel:
_blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
_blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
}
}
}
*** 1304,1316 ****
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
--- 1313,1328 ----
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);
// 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
*** 1348,1360 ****
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:
--- 1360,1375 ----
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);
} else if (y != lastY) {
_cache.clearAARow(y);
}
// update member:
*** 1373,1412 ****
}
if (edgeMinY == Integer.MAX_VALUE) {
return false; // undefined edges bounds
}
! final int _boundsMinY = boundsMinY;
! final int _boundsMaxY = boundsMaxY;
!
! // bounds as inclusive intervals
final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX);
! final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX - 1);
// edge Min/Max Y are already rounded to subpixels within bounds:
final int spminY = edgeMinY;
! final int spmaxY;
! int maxY = edgeMaxY;
! if (maxY <= _boundsMaxY - 1) {
! spmaxY = maxY;
! } else {
! spmaxY = _boundsMaxY - 1;
! maxY = _boundsMaxY;
! }
! buckets_minY = spminY - _boundsMinY;
! buckets_maxY = maxY - _boundsMinY;
if (DO_LOG_BOUNDS) {
MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
! + "][" + edgeMinY + " ... " + edgeMaxY + "]");
MarlinUtils.logInfo("spXY = [" + spminX + " ... " + spmaxX
! + "][" + spminY + " ... " + spmaxY + "]");
}
// test clipping for shapes out of bounds
! if ((spminX > spmaxX) || (spminY > spmaxY)) {
return false;
}
// half open intervals
// inclusive:
--- 1388,1417 ----
}
if (edgeMinY == Integer.MAX_VALUE) {
return false; // undefined edges bounds
}
! // bounds as half-open intervals
final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX);
! final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX);
// edge Min/Max Y are already rounded to subpixels within bounds:
final int spminY = edgeMinY;
! final int spmaxY = edgeMaxY;
! buckets_minY = spminY - boundsMinY;
! buckets_maxY = spmaxY - boundsMinY;
if (DO_LOG_BOUNDS) {
MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
! + "[ [" + edgeMinY + " ... " + edgeMaxY + "[");
MarlinUtils.logInfo("spXY = [" + spminX + " ... " + spmaxX
! + "[ [" + spminY + " ... " + spmaxY + "[");
}
// test clipping for shapes out of bounds
! if ((spminX >= spmaxX) || (spminY >= spmaxY)) {
return false;
}
// half open intervals
// inclusive:
*** 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:
--- 1422,1444 ----
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);
// 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 blkLen = ((pmaxX - pminX) >> BLOCK_SIZE_LG) + 2;
! if (blkLen > INITIAL_ARRAY) {
! blkFlags = blkFlags_ref.getArray(blkLen);
}
}
}
// memorize the rendering bounding box:
*** 1444,1454 ****
// exclusive:
bbox_spmaxX = pmaxX << SUBPIXEL_LG_POSITIONS_X;
// inclusive:
bbox_spminY = spminY;
// exclusive:
! bbox_spmaxY = FloatMath.min(spmaxY + 1, pmaxY << SUBPIXEL_LG_POSITIONS_Y);
if (DO_LOG_BOUNDS) {
MarlinUtils.logInfo("pXY = [" + pminX + " ... " + pmaxX
+ "[ [" + pminY + " ... " + pmaxY + "[");
MarlinUtils.logInfo("bbox_spXY = [" + bbox_spminX + " ... "
--- 1449,1459 ----
// exclusive:
bbox_spmaxX = pmaxX << SUBPIXEL_LG_POSITIONS_X;
// inclusive:
bbox_spminY = spminY;
// exclusive:
! bbox_spmaxY = spmaxY;
if (DO_LOG_BOUNDS) {
MarlinUtils.logInfo("pXY = [" + pminX + " ... " + pmaxX
+ "[ [" + pminY + " ... " + pmaxY + "[");
MarlinUtils.logInfo("bbox_spXY = [" + bbox_spminX + " ... "
*** 1502,1511 ****
--- 1507,1519 ----
void copyAARow(final int[] alphaRow,
final int pix_y, final int pix_from, final int pix_to,
final boolean useBlockFlags)
{
+ if (DO_MONITORS) {
+ rdrCtx.stats.mon_rdr_copyAARow.start();
+ }
if (useBlockFlags) {
if (DO_STATS) {
rdrCtx.stats.hist_tile_generator_encoding.add(1);
}
cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to);
*** 1513,1519 ****
--- 1521,1530 ----
if (DO_STATS) {
rdrCtx.stats.hist_tile_generator_encoding.add(0);
}
cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
}
+ if (DO_MONITORS) {
+ rdrCtx.stats.mon_rdr_copyAARow.stop();
+ }
}
}
< prev index next >