58 final byte[] _ALPHA_MAP = buildAlphaMap(MAX_AA_ALPHA); |
58 final byte[] _ALPHA_MAP = buildAlphaMap(MAX_AA_ALPHA); |
59 |
59 |
60 ALPHA_MAP_UNSAFE = new OffHeapArray(_ALPHA_MAP, _ALPHA_MAP.length); // 1K |
60 ALPHA_MAP_UNSAFE = new OffHeapArray(_ALPHA_MAP, _ALPHA_MAP.length); // 1K |
61 ALPHA_MAP =_ALPHA_MAP; |
61 ALPHA_MAP =_ALPHA_MAP; |
62 |
62 |
63 final Unsafe _unsafe = OffHeapArray.unsafe; |
63 final Unsafe _unsafe = OffHeapArray.UNSAFE; |
64 final long addr = ALPHA_MAP_UNSAFE.address; |
64 final long addr = ALPHA_MAP_UNSAFE.address; |
65 |
65 |
66 for (int i = 0; i < _ALPHA_MAP.length; i++) { |
66 for (int i = 0; i < _ALPHA_MAP.length; i++) { |
67 _unsafe.putByte(addr + i, _ALPHA_MAP[i]); |
67 _unsafe.putByte(addr + i, _ALPHA_MAP[i]); |
68 } |
68 } |
155 // note: already checked (meanCrossingPerPixel <= 2) |
155 // note: already checked (meanCrossingPerPixel <= 2) |
156 // rewritten to avoid division: |
156 // rewritten to avoid division: |
157 || (width * heightSubPixel) > |
157 || (width * heightSubPixel) > |
158 ((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG); |
158 ((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG); |
159 |
159 |
160 if (doTrace && !useRLE) { |
160 if (DO_TRACE && !useRLE) { |
161 final float meanCrossings |
161 final float meanCrossings |
162 = ((float) edgeSumDeltaY) / heightSubPixel; |
162 = ((float) edgeSumDeltaY) / heightSubPixel; |
163 final float meanDist = width / (meanCrossings - 1); |
163 final float meanDist = width / (meanCrossings - 1); |
164 |
164 |
165 System.out.println("High complexity: " |
165 System.out.println("High complexity: " |
178 |
178 |
179 // the ceiling of (maxy - miny + 1) / TILE_SIZE; |
179 // the ceiling of (maxy - miny + 1) / TILE_SIZE; |
180 final int nxTiles = (width + TILE_SIZE) >> TILE_SIZE_LG; |
180 final int nxTiles = (width + TILE_SIZE) >> TILE_SIZE_LG; |
181 |
181 |
182 if (nxTiles > INITIAL_ARRAY) { |
182 if (nxTiles > INITIAL_ARRAY) { |
183 if (doStats) { |
183 if (DO_STATS) { |
184 RendererContext.stats.stat_array_marlincache_touchedTile |
184 rdrCtx.stats.stat_array_marlincache_touchedTile |
185 .add(nxTiles); |
185 .add(nxTiles); |
186 } |
186 } |
187 touchedTile = rdrCtx.getIntArray(nxTiles); |
187 touchedTile = rdrCtx.getIntArray(nxTiles); |
188 } |
188 } |
189 } |
189 } |
204 // At last: resize back off-heap rowAA to initial size |
204 // At last: resize back off-heap rowAA to initial size |
205 if (rowAAChunk.length != INITIAL_CHUNK_ARRAY) { |
205 if (rowAAChunk.length != INITIAL_CHUNK_ARRAY) { |
206 // note: may throw OOME: |
206 // note: may throw OOME: |
207 rowAAChunk.resize(INITIAL_CHUNK_ARRAY); |
207 rowAAChunk.resize(INITIAL_CHUNK_ARRAY); |
208 } |
208 } |
209 if (doCleanDirty) { |
209 if (DO_CLEAN_DIRTY) { |
210 // Force zero-fill dirty arrays: |
210 // Force zero-fill dirty arrays: |
211 rowAAChunk.fill(BYTE_0); |
211 rowAAChunk.fill(BYTE_0); |
212 } |
212 } |
213 } |
213 } |
214 |
214 |
215 void resetTileLine(final int pminY) { |
215 void resetTileLine(final int pminY) { |
216 // update bboxY0 to process a complete tile line [0 - 32] |
216 // update bboxY0 to process a complete tile line [0 - 32] |
217 bboxY0 = pminY; |
217 bboxY0 = pminY; |
218 |
218 |
219 // reset current pos |
219 // reset current pos |
220 if (doStats) { |
220 if (DO_STATS) { |
221 RendererContext.stats.stat_cache_rowAAChunk.add(rowAAChunkPos); |
221 rdrCtx.stats.stat_cache_rowAAChunk.add(rowAAChunkPos); |
222 } |
222 } |
223 rowAAChunkPos = 0L; |
223 rowAAChunkPos = 0L; |
224 |
224 |
225 // Reset touchedTile: |
225 // Reset touchedTile: |
226 if (tileMin != Integer.MAX_VALUE) { |
226 if (tileMin != Integer.MAX_VALUE) { |
227 if (doStats) { |
227 if (DO_STATS) { |
228 RendererContext.stats.stat_cache_tiles.add(tileMax - tileMin); |
228 rdrCtx.stats.stat_cache_tiles.add(tileMax - tileMin); |
229 } |
229 } |
230 // clean only dirty touchedTile: |
230 // clean only dirty touchedTile: |
231 if (tileMax == 1) { |
231 if (tileMax == 1) { |
232 touchedTile[0] = 0; |
232 touchedTile[0] = 0; |
233 } else { |
233 } else { |
236 // reset tile used marks: |
236 // reset tile used marks: |
237 tileMin = Integer.MAX_VALUE; |
237 tileMin = Integer.MAX_VALUE; |
238 tileMax = Integer.MIN_VALUE; |
238 tileMax = Integer.MIN_VALUE; |
239 } |
239 } |
240 |
240 |
241 if (doCleanDirty) { |
241 if (DO_CLEAN_DIRTY) { |
242 // Force zero-fill dirty arrays: |
242 // Force zero-fill dirty arrays: |
243 rowAAChunk.fill(BYTE_0); |
243 rowAAChunk.fill(BYTE_0); |
244 } |
244 } |
245 } |
245 } |
246 |
246 |
265 * @param px1 last pixel exclusive x1 |
265 * @param px1 last pixel exclusive x1 |
266 */ |
266 */ |
267 void copyAARowNoRLE(final int[] alphaRow, final int y, |
267 void copyAARowNoRLE(final int[] alphaRow, final int y, |
268 final int px0, final int px1) |
268 final int px0, final int px1) |
269 { |
269 { |
270 if (doMonitors) { |
270 if (DO_MONITORS) { |
271 RendererContext.stats.mon_rdr_copyAARow.start(); |
271 rdrCtx.stats.mon_rdr_copyAARow.start(); |
272 } |
272 } |
273 |
273 |
274 // skip useless pixels above boundary |
274 // skip useless pixels above boundary |
275 final int px_bbox1 = FloatMath.min(px1, bboxX1); |
275 final int px_bbox1 = FloatMath.min(px1, bboxX1); |
276 |
276 |
277 if (doLogBounds) { |
277 if (DO_LOG_BOUNDS) { |
278 MarlinUtils.logInfo("row = [" + px0 + " ... " + px_bbox1 |
278 MarlinUtils.logInfo("row = [" + px0 + " ... " + px_bbox1 |
279 + " (" + px1 + ") [ for y=" + y); |
279 + " (" + px1 + ") [ for y=" + y); |
280 } |
280 } |
281 |
281 |
282 final int row = y - bboxY0; |
282 final int row = y - bboxY0; |
303 final OffHeapArray _rowAAChunk = rowAAChunk; |
303 final OffHeapArray _rowAAChunk = rowAAChunk; |
304 // ensure rowAAChunk capacity: |
304 // ensure rowAAChunk capacity: |
305 if (_rowAAChunk.length < needSize) { |
305 if (_rowAAChunk.length < needSize) { |
306 expandRowAAChunk(needSize); |
306 expandRowAAChunk(needSize); |
307 } |
307 } |
308 if (doStats) { |
308 if (DO_STATS) { |
309 RendererContext.stats.stat_cache_rowAA.add(px_bbox1 - px0); |
309 rdrCtx.stats.stat_cache_rowAA.add(px_bbox1 - px0); |
310 } |
310 } |
311 |
311 |
312 // rowAA contains only alpha values for range[x0; x1[ |
312 // rowAA contains only alpha values for range[x0; x1[ |
313 final int[] _touchedTile = touchedTile; |
313 final int[] _touchedTile = touchedTile; |
314 final int _TILE_SIZE_LG = TILE_SIZE_LG; |
314 final int _TILE_SIZE_LG = TILE_SIZE_LG; |
315 |
315 |
316 final int from = px0 - bboxX0; // first pixel inclusive |
316 final int from = px0 - bboxX0; // first pixel inclusive |
317 final int to = px_bbox1 - bboxX0; // last pixel exclusive |
317 final int to = px_bbox1 - bboxX0; // last pixel exclusive |
318 |
318 |
319 final Unsafe _unsafe = OffHeapArray.unsafe; |
319 final Unsafe _unsafe = OffHeapArray.UNSAFE; |
320 final long SIZE_BYTE = 1L; |
320 final long SIZE_BYTE = 1L; |
321 final long addr_alpha = ALPHA_MAP_UNSAFE.address; |
321 final long addr_alpha = ALPHA_MAP_UNSAFE.address; |
322 long addr_off = _rowAAChunk.address + pos; |
322 long addr_off = _rowAAChunk.address + pos; |
323 |
323 |
324 // compute alpha sum into rowAA: |
324 // compute alpha sum into rowAA: |
359 tx = ((to - 1) >> _TILE_SIZE_LG) + 1; // exclusive (+1 to be sure) |
359 tx = ((to - 1) >> _TILE_SIZE_LG) + 1; // exclusive (+1 to be sure) |
360 if (tx > tileMax) { |
360 if (tx > tileMax) { |
361 tileMax = tx; |
361 tileMax = tx; |
362 } |
362 } |
363 |
363 |
364 if (doLogBounds) { |
364 if (DO_LOG_BOUNDS) { |
365 MarlinUtils.logInfo("clear = [" + from + " ... " + to + "["); |
365 MarlinUtils.logInfo("clear = [" + from + " ... " + to + "["); |
366 } |
366 } |
367 |
367 |
368 // Clear alpha row for reuse: |
368 // Clear alpha row for reuse: |
369 IntArrayCache.fill(alphaRow, from, px1 - bboxX0, 0); |
369 IntArrayCache.fill(alphaRow, from, px1 - bboxX0, 0); |
370 |
370 |
371 if (doMonitors) { |
371 if (DO_MONITORS) { |
372 RendererContext.stats.mon_rdr_copyAARow.stop(); |
372 rdrCtx.stats.mon_rdr_copyAARow.stop(); |
373 } |
373 } |
374 } |
374 } |
375 |
375 |
376 void copyAARowRLE_WithBlockFlags(final int[] blkFlags, final int[] alphaRow, |
376 void copyAARowRLE_WithBlockFlags(final int[] blkFlags, final int[] alphaRow, |
377 final int y, final int px0, final int px1) |
377 final int y, final int px0, final int px1) |
378 { |
378 { |
379 if (doMonitors) { |
379 if (DO_MONITORS) { |
380 RendererContext.stats.mon_rdr_copyAARow.start(); |
380 rdrCtx.stats.mon_rdr_copyAARow.start(); |
381 } |
381 } |
382 |
382 |
383 // Copy rowAA data into the piscesCache if one is present |
383 // Copy rowAA data into the piscesCache if one is present |
384 final int _bboxX0 = bboxX0; |
384 final int _bboxX0 = bboxX0; |
385 |
385 |
389 |
389 |
390 // skip useless pixels above boundary |
390 // skip useless pixels above boundary |
391 final int px_bbox1 = FloatMath.min(px1, bboxX1); |
391 final int px_bbox1 = FloatMath.min(px1, bboxX1); |
392 final int to = px_bbox1 - _bboxX0; // last pixel exclusive |
392 final int to = px_bbox1 - _bboxX0; // last pixel exclusive |
393 |
393 |
394 if (doLogBounds) { |
394 if (DO_LOG_BOUNDS) { |
395 MarlinUtils.logInfo("row = [" + px0 + " ... " + px_bbox1 |
395 MarlinUtils.logInfo("row = [" + px0 + " ... " + px_bbox1 |
396 + " (" + px1 + ") [ for y=" + y); |
396 + " (" + px1 + ") [ for y=" + y); |
397 } |
397 } |
398 |
398 |
399 // get current position: |
399 // get current position: |
408 // ensure rowAAChunk capacity: |
408 // ensure rowAAChunk capacity: |
409 if (_rowAAChunk.length < needSize) { |
409 if (_rowAAChunk.length < needSize) { |
410 expandRowAAChunk(needSize); |
410 expandRowAAChunk(needSize); |
411 } |
411 } |
412 |
412 |
413 final Unsafe _unsafe = OffHeapArray.unsafe; |
413 final Unsafe _unsafe = OffHeapArray.UNSAFE; |
414 final long SIZE_INT = 4L; |
414 final long SIZE_INT = 4L; |
415 final long addr_alpha = ALPHA_MAP_UNSAFE.address; |
415 final long addr_alpha = ALPHA_MAP_UNSAFE.address; |
416 long addr_off = _rowAAChunk.address + initialPos; |
416 long addr_off = _rowAAChunk.address + initialPos; |
417 |
417 |
418 final int[] _touchedTile = touchedTile; |
418 final int[] _touchedTile = touchedTile; |
463 // absX is the absolute x-coordinate: |
463 // absX is the absolute x-coordinate: |
464 // note: last pixel exclusive (>= 0) |
464 // note: last pixel exclusive (>= 0) |
465 // note: it should check X is smaller than 23bits (overflow)! |
465 // note: it should check X is smaller than 23bits (overflow)! |
466 |
466 |
467 // check address alignment to 4 bytes: |
467 // check address alignment to 4 bytes: |
468 if (doCheckUnsafe) { |
468 if (DO_CHECK_UNSAFE) { |
469 if ((addr_off & 3) != 0) { |
469 if ((addr_off & 3) != 0) { |
470 MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off); |
470 MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off); |
471 } |
471 } |
472 } |
472 } |
473 |
473 |
526 // absX is the absolute x-coordinate in bits 31 to 8 and val in bits 0..7 |
526 // absX is the absolute x-coordinate in bits 31 to 8 and val in bits 0..7 |
527 // note: last pixel exclusive (>= 0) |
527 // note: last pixel exclusive (>= 0) |
528 // note: it should check X is smaller than 23bits (overflow)! |
528 // note: it should check X is smaller than 23bits (overflow)! |
529 |
529 |
530 // check address alignment to 4 bytes: |
530 // check address alignment to 4 bytes: |
531 if (doCheckUnsafe) { |
531 if (DO_CHECK_UNSAFE) { |
532 if ((addr_off & 3) != 0) { |
532 if ((addr_off & 3) != 0) { |
533 MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off); |
533 MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off); |
534 } |
534 } |
535 } |
535 } |
536 |
536 |
551 touchTile(cx0, val, to, runLen, _touchedTile); |
551 touchTile(cx0, val, to, runLen, _touchedTile); |
552 } |
552 } |
553 } |
553 } |
554 addr_off += SIZE_INT; |
554 addr_off += SIZE_INT; |
555 |
555 |
556 if (doStats) { |
556 if (DO_STATS) { |
557 RendererContext.stats.hist_tile_generator_encoding_runLen |
557 rdrCtx.stats.hist_tile_generator_encoding_runLen |
558 .add(runLen); |
558 .add(runLen); |
559 } |
559 } |
560 |
560 |
561 long len = (addr_off - _rowAAChunk.address); |
561 long len = (addr_off - _rowAAChunk.address); |
562 |
562 |
564 rowAALen[row] = (len - initialPos); |
564 rowAALen[row] = (len - initialPos); |
565 |
565 |
566 // update current position: |
566 // update current position: |
567 rowAAChunkPos = len; |
567 rowAAChunkPos = len; |
568 |
568 |
569 if (doStats) { |
569 if (DO_STATS) { |
570 RendererContext.stats.stat_cache_rowAA.add(rowAALen[row]); |
570 rdrCtx.stats.stat_cache_rowAA.add(rowAALen[row]); |
571 RendererContext.stats.hist_tile_generator_encoding_ratio.add( |
571 rdrCtx.stats.hist_tile_generator_encoding_ratio.add( |
572 (100 * skip) / (blkE - blkW) |
572 (100 * skip) / (blkE - blkW) |
573 ); |
573 ); |
574 } |
574 } |
575 |
575 |
576 // update tile used marks: |
576 // update tile used marks: |
587 // Clear alpha row for reuse: |
587 // Clear alpha row for reuse: |
588 if (px1 > bboxX1) { |
588 if (px1 > bboxX1) { |
589 alphaRow[to ] = 0; |
589 alphaRow[to ] = 0; |
590 alphaRow[to + 1] = 0; |
590 alphaRow[to + 1] = 0; |
591 } |
591 } |
592 if (doChecks) { |
592 if (DO_CHECKS) { |
593 IntArrayCache.check(blkFlags, blkW, blkE, 0); |
593 IntArrayCache.check(blkFlags, blkW, blkE, 0); |
594 IntArrayCache.check(alphaRow, from, px1 - bboxX0, 0); |
594 IntArrayCache.check(alphaRow, from, px1 - bboxX0, 0); |
595 } |
595 } |
596 |
596 |
597 if (doMonitors) { |
597 if (DO_MONITORS) { |
598 RendererContext.stats.mon_rdr_copyAARow.stop(); |
598 rdrCtx.stats.mon_rdr_copyAARow.stop(); |
599 } |
599 } |
600 } |
600 } |
601 |
601 |
602 long startRLERow(final int row, final int x0, final int x1) { |
602 long startRLERow(final int row, final int x0, final int x1) { |
603 // rows are supposed to be added by increasing y. |
603 // rows are supposed to be added by increasing y. |
609 // update row index to current position: |
609 // update row index to current position: |
610 return (rowAAChunkIndex[row] = rowAAChunkPos); |
610 return (rowAAChunkIndex[row] = rowAAChunkPos); |
611 } |
611 } |
612 |
612 |
613 private void expandRowAAChunk(final long needSize) { |
613 private void expandRowAAChunk(final long needSize) { |
614 if (doStats) { |
614 if (DO_STATS) { |
615 RendererContext.stats.stat_array_marlincache_rowAAChunk |
615 rdrCtx.stats.stat_array_marlincache_rowAAChunk |
616 .add(needSize); |
616 .add(needSize); |
617 } |
617 } |
618 |
618 |
619 // note: throw IOOB if neededSize > 2Gb: |
619 // note: throw IOOB if neededSize > 2Gb: |
620 final long newSize = ArrayCache.getNewLargeSize(rowAAChunk.length, needSize); |
620 final long newSize = ArrayCache.getNewLargeSize(rowAAChunk.length, needSize); |