23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package sun.java2d.marlin; |
26 package sun.java2d.marlin; |
27 |
27 |
28 import java.util.Arrays; |
|
29 import sun.awt.geom.PathConsumer2D; |
28 import sun.awt.geom.PathConsumer2D; |
30 import static sun.java2d.marlin.OffHeapArray.SIZE_INT; |
29 import static sun.java2d.marlin.OffHeapArray.SIZE_INT; |
31 import jdk.internal.misc.Unsafe; |
30 import jdk.internal.misc.Unsafe; |
32 |
31 |
33 final class Renderer implements PathConsumer2D, MarlinConst { |
32 final class Renderer implements PathConsumer2D, MarlinRenderer { |
34 |
33 |
35 static final boolean DISABLE_RENDER = false; |
34 static final boolean DISABLE_RENDER = false; |
36 |
35 |
37 static final boolean ENABLE_BLOCK_FLAGS = MarlinProperties.isUseTileFlags(); |
36 static final boolean ENABLE_BLOCK_FLAGS = MarlinProperties.isUseTileFlags(); |
38 static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics(); |
37 static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics(); |
39 |
38 |
40 private static final int ALL_BUT_LSB = 0xfffffffe; |
39 private static final int ALL_BUT_LSB = 0xFFFFFFFE; |
41 private static final int ERR_STEP_MAX = 0x7fffffff; // = 2^31 - 1 |
40 private static final int ERR_STEP_MAX = 0x7FFFFFFF; // = 2^31 - 1 |
42 |
41 |
43 private static final double POWER_2_TO_32 = 0x1.0p32; |
42 private static final double POWER_2_TO_32 = 0x1.0p32d; |
44 |
43 |
45 // use float to make tosubpix methods faster (no int to float conversion) |
44 // use float to make tosubpix methods faster (no int to float conversion) |
46 public static final float F_SUBPIXEL_POSITIONS_X |
45 static final float SUBPIXEL_SCALE_X = (float) SUBPIXEL_POSITIONS_X; |
47 = (float) SUBPIXEL_POSITIONS_X; |
46 static final float SUBPIXEL_SCALE_Y = (float) SUBPIXEL_POSITIONS_Y; |
48 public static final float F_SUBPIXEL_POSITIONS_Y |
47 static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1; |
49 = (float) SUBPIXEL_POSITIONS_Y; |
48 static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1; |
50 public static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1; |
|
51 public static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1; |
|
52 |
49 |
53 // number of subpixels corresponding to a tile line |
50 // number of subpixels corresponding to a tile line |
54 private static final int SUBPIXEL_TILE |
51 private static final int SUBPIXEL_TILE |
55 = TILE_SIZE << SUBPIXEL_LG_POSITIONS_Y; |
52 = TILE_H << SUBPIXEL_LG_POSITIONS_Y; |
56 |
53 |
57 // 2048 (pixelSize) pixels (height) x 8 subpixels = 64K |
54 // 2048 (pixelSize) pixels (height) x 8 subpixels = 64K |
58 static final int INITIAL_BUCKET_ARRAY |
55 static final int INITIAL_BUCKET_ARRAY |
59 = INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y; |
56 = INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y; |
60 |
57 |
61 // crossing capacity = edges count / 8 ~ 512 |
58 // crossing capacity = edges count / 4 ~ 1024 |
62 static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 3; |
59 static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 2; |
63 |
60 |
64 public static final int WIND_EVEN_ODD = 0; |
61 public static final int WIND_EVEN_ODD = 0; |
65 public static final int WIND_NON_ZERO = 1; |
62 public static final int WIND_NON_ZERO = 1; |
66 |
63 |
67 // common to all types of input path segments. |
64 // common to all types of input path segments. |
78 public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT); |
75 public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT); |
79 |
76 |
80 // curve break into lines |
77 // curve break into lines |
81 // cubic error in subpixels to decrement step |
78 // cubic error in subpixels to decrement step |
82 private static final float CUB_DEC_ERR_SUBPIX |
79 private static final float CUB_DEC_ERR_SUBPIX |
83 = 2.5f * (NORM_SUBPIXELS / 8f); // 2.5 subpixel for typical 8x8 subpixels |
80 = MarlinProperties.getCubicDecD2() * (NORM_SUBPIXELS / 8.0f); // 1 pixel |
84 // cubic error in subpixels to increment step |
81 // cubic error in subpixels to increment step |
85 private static final float CUB_INC_ERR_SUBPIX |
82 private static final float CUB_INC_ERR_SUBPIX |
86 = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels |
83 = MarlinProperties.getCubicIncD1() * (NORM_SUBPIXELS / 8.0f); // 0.4 pixel |
87 |
84 |
88 // cubic bind length to decrement step = 8 * error in subpixels |
85 // TestNonAARasterization (JDK-8170879): cubics |
89 // pisces: 20 / 8 |
86 // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07) |
90 // openjfx pisces: 8 / 3.2 |
87 |
91 // multiply by 8 = error scale factor: |
88 // cubic bind length to decrement step |
92 public static final float CUB_DEC_BND |
89 public static final float CUB_DEC_BND |
93 = 8f * CUB_DEC_ERR_SUBPIX; // 20f means 2.5 subpixel error |
90 = 8.0f * CUB_DEC_ERR_SUBPIX; |
94 // cubic bind length to increment step = 8 * error in subpixels |
91 // cubic bind length to increment step |
95 public static final float CUB_INC_BND |
92 public static final float CUB_INC_BND |
96 = 8f * CUB_INC_ERR_SUBPIX; // 8f means 1 subpixel error |
93 = 8.0f * CUB_INC_ERR_SUBPIX; |
97 |
94 |
98 // cubic countlg |
95 // cubic countlg |
99 public static final int CUB_COUNT_LG = 2; |
96 public static final int CUB_COUNT_LG = 2; |
100 // cubic count = 2^countlg |
97 // cubic count = 2^countlg |
101 private static final int CUB_COUNT = 1 << CUB_COUNT_LG; |
98 private static final int CUB_COUNT = 1 << CUB_COUNT_LG; |
102 // cubic count^2 = 4^countlg |
99 // cubic count^2 = 4^countlg |
103 private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG); |
100 private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG); |
104 // cubic count^3 = 8^countlg |
101 // cubic count^3 = 8^countlg |
105 private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG); |
102 private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG); |
106 // cubic dt = 1 / count |
103 // cubic dt = 1 / count |
107 private static final float CUB_INV_COUNT = 1f / CUB_COUNT; |
104 private static final float CUB_INV_COUNT = 1.0f / CUB_COUNT; |
108 // cubic dt^2 = 1 / count^2 = 1 / 4^countlg |
105 // cubic dt^2 = 1 / count^2 = 1 / 4^countlg |
109 private static final float CUB_INV_COUNT_2 = 1f / CUB_COUNT_2; |
106 private static final float CUB_INV_COUNT_2 = 1.0f / CUB_COUNT_2; |
110 // cubic dt^3 = 1 / count^3 = 1 / 8^countlg |
107 // cubic dt^3 = 1 / count^3 = 1 / 8^countlg |
111 private static final float CUB_INV_COUNT_3 = 1f / CUB_COUNT_3; |
108 private static final float CUB_INV_COUNT_3 = 1.0f / CUB_COUNT_3; |
112 |
109 |
113 // quad break into lines |
110 // quad break into lines |
114 // quadratic error in subpixels |
111 // quadratic error in subpixels |
115 private static final float QUAD_DEC_ERR_SUBPIX |
112 private static final float QUAD_DEC_ERR_SUBPIX |
116 = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels |
113 = MarlinProperties.getQuadDecD2() * (NORM_SUBPIXELS / 8.0f); // 0.5 pixel |
117 |
114 |
118 // quadratic bind length to decrement step = 8 * error in subpixels |
115 // TestNonAARasterization (JDK-8170879): quads |
119 // pisces and openjfx pisces: 32 |
116 // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10) |
|
117 |
|
118 // quadratic bind length to decrement step |
120 public static final float QUAD_DEC_BND |
119 public static final float QUAD_DEC_BND |
121 = 8f * QUAD_DEC_ERR_SUBPIX; // 8f means 1 subpixel error |
120 = 8.0f * QUAD_DEC_ERR_SUBPIX; |
122 |
121 |
123 ////////////////////////////////////////////////////////////////////////////// |
122 ////////////////////////////////////////////////////////////////////////////// |
124 // SCAN LINE |
123 // SCAN LINE |
125 ////////////////////////////////////////////////////////////////////////////// |
124 ////////////////////////////////////////////////////////////////////////////// |
126 // crossings ie subpixel edge x coordinates |
125 // crossings ie subpixel edge x coordinates |
155 private int edgeMinY = Integer.MAX_VALUE; |
154 private int edgeMinY = Integer.MAX_VALUE; |
156 private int edgeMaxY = Integer.MIN_VALUE; |
155 private int edgeMaxY = Integer.MIN_VALUE; |
157 private float edgeMinX = Float.POSITIVE_INFINITY; |
156 private float edgeMinX = Float.POSITIVE_INFINITY; |
158 private float edgeMaxX = Float.NEGATIVE_INFINITY; |
157 private float edgeMaxX = Float.NEGATIVE_INFINITY; |
159 |
158 |
160 // edges [floats|ints] stored in off-heap memory |
159 // edges [ints] stored in off-heap memory |
161 private final OffHeapArray edges; |
160 private final OffHeapArray edges; |
162 |
161 |
163 private int[] edgeBuckets; |
162 private int[] edgeBuckets; |
164 private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed) |
163 private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed) |
165 // used range for edgeBuckets / edgeBucketCounts |
164 // used range for edgeBuckets / edgeBucketCounts |
166 private int buckets_minY; |
165 private int buckets_minY; |
167 private int buckets_maxY; |
166 private int buckets_maxY; |
168 // sum of each edge delta Y (subpixels) |
|
169 private int edgeSumDeltaY; |
|
170 |
167 |
171 // edgeBuckets ref (clean) |
168 // edgeBuckets ref (clean) |
172 private final IntArrayCache.Reference edgeBuckets_ref; |
169 private final IntArrayCache.Reference edgeBuckets_ref; |
173 // edgeBucketCounts ref (clean) |
170 // edgeBucketCounts ref (clean) |
174 private final IntArrayCache.Reference edgeBucketCounts_ref; |
171 private final IntArrayCache.Reference edgeBucketCounts_ref; |
181 final float x2, final float y2) |
178 final float x2, final float y2) |
182 { |
179 { |
183 int count = 1; // dt = 1 / count |
180 int count = 1; // dt = 1 / count |
184 |
181 |
185 // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1) |
182 // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1) |
186 float maxDD = FloatMath.max(Math.abs(c.dbx), Math.abs(c.dby)); |
183 float maxDD = Math.abs(c.dbx) + Math.abs(c.dby); |
187 |
184 |
188 final float _DEC_BND = QUAD_DEC_BND; |
185 final float _DEC_BND = QUAD_DEC_BND; |
189 |
186 |
190 while (maxDD >= _DEC_BND) { |
187 while (maxDD >= _DEC_BND) { |
191 // divide step by half: |
188 // divide step by half: |
192 maxDD /= 4f; // error divided by 2^2 = 4 |
189 maxDD /= 4.0f; // error divided by 2^2 = 4 |
193 |
190 |
194 count <<= 1; |
191 count <<= 1; |
195 if (DO_STATS) { |
192 if (DO_STATS) { |
196 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count); |
193 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count); |
197 } |
194 } |
198 } |
195 } |
199 |
196 |
200 int nL = 0; // line count |
197 int nL = 0; // line count |
201 if (count > 1) { |
198 if (count > 1) { |
202 final float icount = 1f / count; // dt |
199 final float icount = 1.0f / count; // dt |
203 final float icount2 = icount * icount; // dt^2 |
200 final float icount2 = icount * icount; // dt^2 |
204 |
201 |
205 final float ddx = c.dbx * icount2; |
202 final float ddx = c.dbx * icount2; |
206 final float ddy = c.dby * icount2; |
203 final float ddy = c.dby * icount2; |
207 float dx = c.bx * icount2 + c.cx * icount; |
204 float dx = c.bx * icount2 + c.cx * icount; |
244 final float icount3 = CUB_INV_COUNT_3; // dt^3 |
241 final float icount3 = CUB_INV_COUNT_3; // dt^3 |
245 |
242 |
246 // the dx and dy refer to forward differencing variables, not the last |
243 // the dx and dy refer to forward differencing variables, not the last |
247 // coefficients of the "points" polynomial |
244 // coefficients of the "points" polynomial |
248 float dddx, dddy, ddx, ddy, dx, dy; |
245 float dddx, dddy, ddx, ddy, dx, dy; |
249 dddx = 2f * c.dax * icount3; |
246 dddx = 2.0f * c.dax * icount3; |
250 dddy = 2f * c.day * icount3; |
247 dddy = 2.0f * c.day * icount3; |
251 ddx = dddx + c.dbx * icount2; |
248 ddx = dddx + c.dbx * icount2; |
252 ddy = dddy + c.dby * icount2; |
249 ddy = dddy + c.dby * icount2; |
253 dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount; |
250 dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount; |
254 dy = c.ay * icount3 + c.by * icount2 + c.cy * icount; |
251 dy = c.ay * icount3 + c.by * icount2 + c.cy * icount; |
255 |
252 |
260 final float _DEC_BND = CUB_DEC_BND; |
257 final float _DEC_BND = CUB_DEC_BND; |
261 final float _INC_BND = CUB_INC_BND; |
258 final float _INC_BND = CUB_INC_BND; |
262 |
259 |
263 while (count > 0) { |
260 while (count > 0) { |
264 // divide step by half: |
261 // divide step by half: |
265 while (Math.abs(ddx) >= _DEC_BND || Math.abs(ddy) >= _DEC_BND) { |
262 while (Math.abs(ddx) + Math.abs(ddy) >= _DEC_BND) { |
266 dddx /= 8f; |
263 dddx /= 8.0f; |
267 dddy /= 8f; |
264 dddy /= 8.0f; |
268 ddx = ddx/4f - dddx; |
265 ddx = ddx / 4.0f - dddx; |
269 ddy = ddy/4f - dddy; |
266 ddy = ddy / 4.0f - dddy; |
270 dx = (dx - ddx) / 2f; |
267 dx = (dx - ddx) / 2.0f; |
271 dy = (dy - ddy) / 2f; |
268 dy = (dy - ddy) / 2.0f; |
272 |
269 |
273 count <<= 1; |
270 count <<= 1; |
274 if (DO_STATS) { |
271 if (DO_STATS) { |
275 rdrCtx.stats.stat_rdr_curveBreak_dec.add(count); |
272 rdrCtx.stats.stat_rdr_curveBreak_dec.add(count); |
276 } |
273 } |
277 } |
274 } |
278 |
275 |
279 // double step: |
276 // double step: |
280 // TODO: why use first derivative dX|Y instead of second ddX|Y ? |
|
281 // both scale changes should use speed or acceleration to have the same metric. |
|
282 |
|
283 // can only do this on even "count" values, because we must divide count by 2 |
277 // can only do this on even "count" values, because we must divide count by 2 |
284 while (count % 2 == 0 |
278 while (count % 2 == 0 |
285 && Math.abs(dx) <= _INC_BND && Math.abs(dy) <= _INC_BND) |
279 && Math.abs(dx) + Math.abs(dy) <= _INC_BND) |
286 { |
280 { |
287 dx = 2f * dx + ddx; |
281 dx = 2.0f * dx + ddx; |
288 dy = 2f * dy + ddy; |
282 dy = 2.0f * dy + ddy; |
289 ddx = 4f * (ddx + dddx); |
283 ddx = 4.0f * (ddx + dddx); |
290 ddy = 4f * (ddy + dddy); |
284 ddy = 4.0f * (ddy + dddy); |
291 dddx *= 8f; |
285 dddx *= 8.0f; |
292 dddy *= 8f; |
286 dddy *= 8.0f; |
293 |
287 |
294 count >>= 1; |
288 count >>= 1; |
295 if (DO_STATS) { |
289 if (DO_STATS) { |
296 rdrCtx.stats.stat_rdr_curveBreak_inc.add(count); |
290 rdrCtx.stats.stat_rdr_curveBreak_inc.add(count); |
297 } |
291 } |
437 // epsilon is hard to pin down in floating point, but easy in fixed point, so if |
431 // epsilon is hard to pin down in floating point, but easy in fixed point, so if |
438 // we convert to fixed point then these operations get easier: |
432 // we convert to fixed point then these operations get easier: |
439 // long x1_fixed = x1_intercept * 2^32; (fixed point 32.32 format) |
433 // long x1_fixed = x1_intercept * 2^32; (fixed point 32.32 format) |
440 // curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1) |
434 // curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1) |
441 // = fixed_floor(x1_fixed + 2^31 - 1) |
435 // = fixed_floor(x1_fixed + 2^31 - 1) |
442 // = fixed_floor(x1_fixed + 0x7fffffff) |
436 // = fixed_floor(x1_fixed + 0x7FFFFFFF) |
443 // and error = fixed_fract(x1_fixed + 0x7fffffff) |
437 // and error = fixed_fract(x1_fixed + 0x7FFFFFFF) |
444 final double x1_intercept = x1d + (firstCrossing - y1d) * slope; |
438 final double x1_intercept = x1d + (firstCrossing - y1d) * slope; |
445 |
439 |
446 // inlined scalb(x1_intercept, 32): |
440 // inlined scalb(x1_intercept, 32): |
447 final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept)) |
441 final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept)) |
448 + 0x7fffffffL; |
442 + 0x7FFFFFFFL; |
449 // curx: |
443 // curx: |
450 // last bit corresponds to the orientation |
444 // last bit corresponds to the orientation |
451 _unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or); |
445 _unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or); |
452 addr += SIZE_INT; |
446 addr += SIZE_INT; |
453 _unsafe.putInt(addr, ((int) x1_fixed_biased) >>> 1); |
447 _unsafe.putInt(addr, ((int) x1_fixed_biased) >>> 1); |
472 final int bucketIdx = firstCrossing - _boundsMinY; |
466 final int bucketIdx = firstCrossing - _boundsMinY; |
473 |
467 |
474 // pointer from bucket |
468 // pointer from bucket |
475 _unsafe.putInt(addr, _edgeBuckets[bucketIdx]); |
469 _unsafe.putInt(addr, _edgeBuckets[bucketIdx]); |
476 addr += SIZE_INT; |
470 addr += SIZE_INT; |
477 // y max (inclusive) |
471 // y max (exclusive) |
478 _unsafe.putInt(addr, lastCrossing); |
472 _unsafe.putInt(addr, lastCrossing); |
479 |
473 |
480 // Update buckets: |
474 // Update buckets: |
481 // directly the edge struct "pointer" |
475 // directly the edge struct "pointer" |
482 _edgeBuckets[bucketIdx] = edgePtr; |
476 _edgeBuckets[bucketIdx] = edgePtr; |
483 _edgeBucketCounts[bucketIdx] += 2; // 1 << 1 |
477 _edgeBucketCounts[bucketIdx] += 2; // 1 << 1 |
484 // last bit means edge end |
478 // last bit means edge end |
485 _edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1; |
479 _edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1; |
486 |
480 |
487 // update sum of delta Y (subpixels): |
|
488 edgeSumDeltaY += (lastCrossing - firstCrossing); |
|
489 |
|
490 // update free pointer (ie length in bytes) |
481 // update free pointer (ie length in bytes) |
491 _edges.used += _SIZEOF_EDGE_BYTES; |
482 _edges.used += _SIZEOF_EDGE_BYTES; |
492 |
483 |
493 if (DO_MONITORS) { |
484 if (DO_MONITORS) { |
494 rdrCtx.stats.mon_rdr_addLine.stop(); |
485 rdrCtx.stats.mon_rdr_addLine.stop(); |
1304 minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X; |
1313 minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X; |
1305 maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X; |
1314 maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X; |
1306 |
1315 |
1307 if (maxX >= minX) { |
1316 if (maxX >= minX) { |
1308 // note: alpha array will be zeroed by copyAARow() |
1317 // note: alpha array will be zeroed by copyAARow() |
1309 // +2 because alpha [pix_minX; pix_maxX+1] |
1318 // +1 because alpha [pix_minX; pix_maxX[ |
1310 // fix range [x0; x1[ |
1319 // fix range [x0; x1[ |
1311 copyAARow(_alpha, lastY, minX, maxX + 2, useBlkFlags); |
1320 // note: if x1=bboxx1, then alpha is written up to bboxx1+1 |
|
1321 // inclusive: alpha[bboxx1] ignored, alpha[bboxx1+1] == 0 |
|
1322 // (normally so never cleared below) |
|
1323 copyAARow(_alpha, lastY, minX, maxX + 1, useBlkFlags); |
1312 |
1324 |
1313 // speculative for next pixel row (scanline coherence): |
1325 // speculative for next pixel row (scanline coherence): |
1314 if (_enableBlkFlagsHeuristics) { |
1326 if (_enableBlkFlagsHeuristics) { |
1315 // Use block flags if large pixel span and few crossings: |
1327 // Use block flags if large pixel span and few crossings: |
1316 // ie mean(distance between crossings) is larger than |
1328 // ie mean(distance between crossings) is larger than |
1348 minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X; |
1360 minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X; |
1349 maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X; |
1361 maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X; |
1350 |
1362 |
1351 if (maxX >= minX) { |
1363 if (maxX >= minX) { |
1352 // note: alpha array will be zeroed by copyAARow() |
1364 // note: alpha array will be zeroed by copyAARow() |
1353 // +2 because alpha [pix_minX; pix_maxX+1] |
1365 // +1 because alpha [pix_minX; pix_maxX[ |
1354 // fix range [x0; x1[ |
1366 // fix range [x0; x1[ |
1355 copyAARow(_alpha, y, minX, maxX + 2, useBlkFlags); |
1367 // note: if x1=bboxx1, then alpha is written up to bboxx1+1 |
|
1368 // inclusive: alpha[bboxx1] ignored then cleared and |
|
1369 // alpha[bboxx1+1] == 0 (normally so never cleared after) |
|
1370 copyAARow(_alpha, y, minX, maxX + 1, useBlkFlags); |
1356 } else if (y != lastY) { |
1371 } else if (y != lastY) { |
1357 _cache.clearAARow(y); |
1372 _cache.clearAARow(y); |
1358 } |
1373 } |
1359 |
1374 |
1360 // update member: |
1375 // update member: |
1373 } |
1388 } |
1374 if (edgeMinY == Integer.MAX_VALUE) { |
1389 if (edgeMinY == Integer.MAX_VALUE) { |
1375 return false; // undefined edges bounds |
1390 return false; // undefined edges bounds |
1376 } |
1391 } |
1377 |
1392 |
1378 final int _boundsMinY = boundsMinY; |
1393 // bounds as half-open intervals |
1379 final int _boundsMaxY = boundsMaxY; |
|
1380 |
|
1381 // bounds as inclusive intervals |
|
1382 final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX); |
1394 final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX); |
1383 final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX - 1); |
1395 final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX); |
1384 |
1396 |
1385 // edge Min/Max Y are already rounded to subpixels within bounds: |
1397 // edge Min/Max Y are already rounded to subpixels within bounds: |
1386 final int spminY = edgeMinY; |
1398 final int spminY = edgeMinY; |
1387 final int spmaxY; |
1399 final int spmaxY = edgeMaxY; |
1388 int maxY = edgeMaxY; |
1400 |
1389 |
1401 buckets_minY = spminY - boundsMinY; |
1390 if (maxY <= _boundsMaxY - 1) { |
1402 buckets_maxY = spmaxY - boundsMinY; |
1391 spmaxY = maxY; |
|
1392 } else { |
|
1393 spmaxY = _boundsMaxY - 1; |
|
1394 maxY = _boundsMaxY; |
|
1395 } |
|
1396 buckets_minY = spminY - _boundsMinY; |
|
1397 buckets_maxY = maxY - _boundsMinY; |
|
1398 |
1403 |
1399 if (DO_LOG_BOUNDS) { |
1404 if (DO_LOG_BOUNDS) { |
1400 MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX |
1405 MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX |
1401 + "][" + edgeMinY + " ... " + edgeMaxY + "]"); |
1406 + "[ [" + edgeMinY + " ... " + edgeMaxY + "["); |
1402 MarlinUtils.logInfo("spXY = [" + spminX + " ... " + spmaxX |
1407 MarlinUtils.logInfo("spXY = [" + spminX + " ... " + spmaxX |
1403 + "][" + spminY + " ... " + spmaxY + "]"); |
1408 + "[ [" + spminY + " ... " + spmaxY + "["); |
1404 } |
1409 } |
1405 |
1410 |
1406 // test clipping for shapes out of bounds |
1411 // test clipping for shapes out of bounds |
1407 if ((spminX > spmaxX) || (spminY > spmaxY)) { |
1412 if ((spminX >= spmaxX) || (spminY >= spmaxY)) { |
1408 return false; |
1413 return false; |
1409 } |
1414 } |
1410 |
1415 |
1411 // half open intervals |
1416 // half open intervals |
1412 // inclusive: |
1417 // inclusive: |
1417 final int pminY = spminY >> SUBPIXEL_LG_POSITIONS_Y; |
1422 final int pminY = spminY >> SUBPIXEL_LG_POSITIONS_Y; |
1418 // exclusive: |
1423 // exclusive: |
1419 final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y; |
1424 final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y; |
1420 |
1425 |
1421 // store BBox to answer ptg.getBBox(): |
1426 // store BBox to answer ptg.getBBox(): |
1422 this.cache.init(pminX, pminY, pmaxX, pmaxY, edgeSumDeltaY); |
1427 this.cache.init(pminX, pminY, pmaxX, pmaxY); |
1423 |
1428 |
1424 // Heuristics for using block flags: |
1429 // Heuristics for using block flags: |
1425 if (ENABLE_BLOCK_FLAGS) { |
1430 if (ENABLE_BLOCK_FLAGS) { |
1426 enableBlkFlags = this.cache.useRLE; |
1431 enableBlkFlags = this.cache.useRLE; |
1427 prevUseBlkFlags = enableBlkFlags && !ENABLE_BLOCK_FLAGS_HEURISTICS; |
1432 prevUseBlkFlags = enableBlkFlags && !ENABLE_BLOCK_FLAGS_HEURISTICS; |
1428 |
1433 |
1429 if (enableBlkFlags) { |
1434 if (enableBlkFlags) { |
1430 // ensure blockFlags array is large enough: |
1435 // ensure blockFlags array is large enough: |
1431 // note: +2 to ensure enough space left at end |
1436 // note: +2 to ensure enough space left at end |
1432 final int nxTiles = ((pmaxX - pminX) >> TILE_SIZE_LG) + 2; |
1437 final int blkLen = ((pmaxX - pminX) >> BLOCK_SIZE_LG) + 2; |
1433 if (nxTiles > INITIAL_ARRAY) { |
1438 if (blkLen > INITIAL_ARRAY) { |
1434 blkFlags = blkFlags_ref.getArray(nxTiles); |
1439 blkFlags = blkFlags_ref.getArray(blkLen); |
1435 } |
1440 } |
1436 } |
1441 } |
1437 } |
1442 } |
1438 |
1443 |
1439 // memorize the rendering bounding box: |
1444 // memorize the rendering bounding box: |
1502 |
1507 |
1503 void copyAARow(final int[] alphaRow, |
1508 void copyAARow(final int[] alphaRow, |
1504 final int pix_y, final int pix_from, final int pix_to, |
1509 final int pix_y, final int pix_from, final int pix_to, |
1505 final boolean useBlockFlags) |
1510 final boolean useBlockFlags) |
1506 { |
1511 { |
|
1512 if (DO_MONITORS) { |
|
1513 rdrCtx.stats.mon_rdr_copyAARow.start(); |
|
1514 } |
1507 if (useBlockFlags) { |
1515 if (useBlockFlags) { |
1508 if (DO_STATS) { |
1516 if (DO_STATS) { |
1509 rdrCtx.stats.hist_tile_generator_encoding.add(1); |
1517 rdrCtx.stats.hist_tile_generator_encoding.add(1); |
1510 } |
1518 } |
1511 cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to); |
1519 cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to); |