< 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 >