jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java
changeset 39519 21bfc4452441
parent 36457 2daf75025304
child 40421 d5ee65e2b0fb
equal deleted inserted replaced
39518:cf5567d544b4 39519:21bfc4452441
   187         while (maxDD >= _DEC_BND) {
   187         while (maxDD >= _DEC_BND) {
   188             // divide step by half:
   188             // divide step by half:
   189             maxDD /= 4f; // error divided by 2^2 = 4
   189             maxDD /= 4f; // error divided by 2^2 = 4
   190 
   190 
   191             count <<= 1;
   191             count <<= 1;
   192             if (doStats) {
   192             if (DO_STATS) {
   193                 RendererContext.stats.stat_rdr_quadBreak_dec.add(count);
   193                 rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
   194             }
   194             }
   195         }
   195         }
   196 
   196 
   197         int nL = 0; // line count
   197         int nL = 0; // line count
   198         if (count > 1) {
   198         if (count > 1) {
   212                 y1 = y0 + dy;
   212                 y1 = y0 + dy;
   213                 dy += ddy;
   213                 dy += ddy;
   214 
   214 
   215                 addLine(x0, y0, x1, y1);
   215                 addLine(x0, y0, x1, y1);
   216 
   216 
   217                 if (doStats) { nL++; }
   217                 if (DO_STATS) { nL++; }
   218                 x0 = x1;
   218                 x0 = x1;
   219                 y0 = y1;
   219                 y0 = y1;
   220             }
   220             }
   221         }
   221         }
   222         addLine(x0, y0, x2, y2);
   222         addLine(x0, y0, x2, y2);
   223 
   223 
   224         if (doStats) {
   224         if (DO_STATS) {
   225             RendererContext.stats.stat_rdr_quadBreak.add(nL + 1);
   225             rdrCtx.stats.stat_rdr_quadBreak.add(nL + 1);
   226         }
   226         }
   227     }
   227     }
   228 
   228 
   229     // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
   229     // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
   230     // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
   230     // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
   266                 ddy = ddy/4f - dddy;
   266                 ddy = ddy/4f - dddy;
   267                 dx = (dx - ddx) / 2f;
   267                 dx = (dx - ddx) / 2f;
   268                 dy = (dy - ddy) / 2f;
   268                 dy = (dy - ddy) / 2f;
   269 
   269 
   270                 count <<= 1;
   270                 count <<= 1;
   271                 if (doStats) {
   271                 if (DO_STATS) {
   272                     RendererContext.stats.stat_rdr_curveBreak_dec.add(count);
   272                     rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
   273                 }
   273                 }
   274             }
   274             }
   275 
   275 
   276             // double step:
   276             // double step:
   277             // TODO: why use first derivative dX|Y instead of second ddX|Y ?
   277             // TODO: why use first derivative dX|Y instead of second ddX|Y ?
   287                 ddy = 4f * (ddy + dddy);
   287                 ddy = 4f * (ddy + dddy);
   288                 dddx *= 8f;
   288                 dddx *= 8f;
   289                 dddy *= 8f;
   289                 dddy *= 8f;
   290 
   290 
   291                 count >>= 1;
   291                 count >>= 1;
   292                 if (doStats) {
   292                 if (DO_STATS) {
   293                     RendererContext.stats.stat_rdr_curveBreak_inc.add(count);
   293                     rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
   294                 }
   294                 }
   295             }
   295             }
   296             if (--count > 0) {
   296             if (--count > 0) {
   297                 x1 += dx;
   297                 x1 += dx;
   298                 dx += ddx;
   298                 dx += ddx;
   305                 y1 = y3;
   305                 y1 = y3;
   306             }
   306             }
   307 
   307 
   308             addLine(x0, y0, x1, y1);
   308             addLine(x0, y0, x1, y1);
   309 
   309 
   310             if (doStats) { nL++; }
   310             if (DO_STATS) { nL++; }
   311             x0 = x1;
   311             x0 = x1;
   312             y0 = y1;
   312             y0 = y1;
   313         }
   313         }
   314         if (doStats) {
   314         if (DO_STATS) {
   315             RendererContext.stats.stat_rdr_curveBreak.add(nL);
   315             rdrCtx.stats.stat_rdr_curveBreak.add(nL);
   316         }
   316         }
   317     }
   317     }
   318 
   318 
   319     private void addLine(float x1, float y1, float x2, float y2) {
   319     private void addLine(float x1, float y1, float x2, float y2) {
   320         if (doMonitors) {
   320         if (DO_MONITORS) {
   321             RendererContext.stats.mon_rdr_addLine.start();
   321             rdrCtx.stats.mon_rdr_addLine.start();
   322         }
   322         }
   323         if (doStats) {
   323         if (DO_STATS) {
   324             RendererContext.stats.stat_rdr_addLine.add(1);
   324             rdrCtx.stats.stat_rdr_addLine.add(1);
   325         }
   325         }
   326         int or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
   326         int or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
   327         if (y2 < y1) {
   327         if (y2 < y1) {
   328             or = 0;
   328             or = 0;
   329             float tmp = y2;
   329             float tmp = y2;
   347         final int lastCrossing  = FloatMath.min(FloatMath.ceil_int(y2), boundsMaxY);
   347         final int lastCrossing  = FloatMath.min(FloatMath.ceil_int(y2), boundsMaxY);
   348 
   348 
   349         /* skip horizontal lines in pixel space and clip edges
   349         /* skip horizontal lines in pixel space and clip edges
   350            out of y range [boundsMinY; boundsMaxY] */
   350            out of y range [boundsMinY; boundsMaxY] */
   351         if (firstCrossing >= lastCrossing) {
   351         if (firstCrossing >= lastCrossing) {
   352             if (doMonitors) {
   352             if (DO_MONITORS) {
   353                 RendererContext.stats.mon_rdr_addLine.stop();
   353                 rdrCtx.stats.mon_rdr_addLine.stop();
   354             }
   354             }
   355             if (doStats) {
   355             if (DO_STATS) {
   356                 RendererContext.stats.stat_rdr_addLine_skip.add(1);
   356                 rdrCtx.stats.stat_rdr_addLine_skip.add(1);
   357             }
   357             }
   358             return;
   358             return;
   359         }
   359         }
   360 
   360 
   361         // edge min/max X/Y are in subpixel space (inclusive) within bounds:
   361         // edge min/max X/Y are in subpixel space (inclusive) within bounds:
   403             // so doubling size is enough to add needed bytes
   403             // so doubling size is enough to add needed bytes
   404             // note: throw IOOB if neededSize > 2Gb:
   404             // note: throw IOOB if neededSize > 2Gb:
   405             final long edgeNewSize = ArrayCache.getNewLargeSize(_edges.length,
   405             final long edgeNewSize = ArrayCache.getNewLargeSize(_edges.length,
   406                                         edgePtr + _SIZEOF_EDGE_BYTES);
   406                                         edgePtr + _SIZEOF_EDGE_BYTES);
   407 
   407 
   408             if (doStats) {
   408             if (DO_STATS) {
   409                 RendererContext.stats.stat_rdr_edges_resizes.add(edgeNewSize);
   409                 rdrCtx.stats.stat_rdr_edges_resizes.add(edgeNewSize);
   410             }
   410             }
   411             _edges.resize(edgeNewSize);
   411             _edges.resize(edgeNewSize);
   412         }
   412         }
   413 
   413 
   414 
   414 
   415         final Unsafe _unsafe = OffHeapArray.unsafe;
   415         final Unsafe _unsafe = OffHeapArray.UNSAFE;
   416         final long SIZE_INT = 4L;
   416         final long SIZE_INT = 4L;
   417         long addr   = _edges.address + edgePtr;
   417         long addr   = _edges.address + edgePtr;
   418 
   418 
   419         // The x value must be bumped up to its position at the next HPC we will evaluate.
   419         // The x value must be bumped up to its position at the next HPC we will evaluate.
   420         // "firstcrossing" is the (sub)pixel number where the next crossing occurs
   420         // "firstcrossing" is the (sub)pixel number where the next crossing occurs
   484         edgeSumDeltaY += (lastCrossing - firstCrossing);
   484         edgeSumDeltaY += (lastCrossing - firstCrossing);
   485 
   485 
   486         // update free pointer (ie length in bytes)
   486         // update free pointer (ie length in bytes)
   487         _edges.used += _SIZEOF_EDGE_BYTES;
   487         _edges.used += _SIZEOF_EDGE_BYTES;
   488 
   488 
   489         if (doMonitors) {
   489         if (DO_MONITORS) {
   490             RendererContext.stats.mon_rdr_addLine.stop();
   490             rdrCtx.stats.mon_rdr_addLine.stop();
   491         }
   491         }
   492     }
   492     }
   493 
   493 
   494 // END EDGE LIST
   494 // END EDGE LIST
   495 //////////////////////////////////////////////////////////////////////////////
   495 //////////////////////////////////////////////////////////////////////////////
   550             (pix_boundsX + pix_boundsWidth) << SUBPIXEL_LG_POSITIONS_X;
   550             (pix_boundsX + pix_boundsWidth) << SUBPIXEL_LG_POSITIONS_X;
   551         this.boundsMinY =  pix_boundsY << SUBPIXEL_LG_POSITIONS_Y;
   551         this.boundsMinY =  pix_boundsY << SUBPIXEL_LG_POSITIONS_Y;
   552         this.boundsMaxY =
   552         this.boundsMaxY =
   553             (pix_boundsY + pix_boundsHeight) << SUBPIXEL_LG_POSITIONS_Y;
   553             (pix_boundsY + pix_boundsHeight) << SUBPIXEL_LG_POSITIONS_Y;
   554 
   554 
   555         if (doLogBounds) {
   555         if (DO_LOG_BOUNDS) {
   556             MarlinUtils.logInfo("boundsXY = [" + boundsMinX + " ... "
   556             MarlinUtils.logInfo("boundsXY = [" + boundsMinX + " ... "
   557                                 + boundsMaxX + "[ [" + boundsMinY + " ... "
   557                                 + boundsMaxX + "[ [" + boundsMinY + " ... "
   558                                 + boundsMaxY + "[");
   558                                 + boundsMaxY + "[");
   559         }
   559         }
   560 
   560 
   561         // see addLine: ceil(boundsMaxY) => boundsMaxY + 1
   561         // see addLine: ceil(boundsMaxY) => boundsMaxY + 1
   562         // +1 for edgeBucketCounts
   562         // +1 for edgeBucketCounts
   563         final int edgeBucketsLength = (boundsMaxY - boundsMinY) + 1;
   563         final int edgeBucketsLength = (boundsMaxY - boundsMinY) + 1;
   564 
   564 
   565         if (edgeBucketsLength > INITIAL_BUCKET_ARRAY) {
   565         if (edgeBucketsLength > INITIAL_BUCKET_ARRAY) {
   566             if (doStats) {
   566             if (DO_STATS) {
   567                 RendererContext.stats.stat_array_renderer_edgeBuckets
   567                 rdrCtx.stats.stat_array_renderer_edgeBuckets
   568                     .add(edgeBucketsLength);
   568                     .add(edgeBucketsLength);
   569                 RendererContext.stats.stat_array_renderer_edgeBucketCounts
   569                 rdrCtx.stats.stat_array_renderer_edgeBucketCounts
   570                     .add(edgeBucketsLength);
   570                     .add(edgeBucketsLength);
   571             }
   571             }
   572             edgeBuckets = rdrCtx.getIntArray(edgeBucketsLength);
   572             edgeBuckets = rdrCtx.getIntArray(edgeBucketsLength);
   573             edgeBucketCounts = rdrCtx.getIntArray(edgeBucketsLength);
   573             edgeBucketCounts = rdrCtx.getIntArray(edgeBucketsLength);
   574         }
   574         }
   590 
   590 
   591     /**
   591     /**
   592      * Disposes this renderer and recycle it clean up before reusing this instance
   592      * Disposes this renderer and recycle it clean up before reusing this instance
   593      */
   593      */
   594     void dispose() {
   594     void dispose() {
   595         if (doStats) {
   595         if (DO_STATS) {
   596             RendererContext.stats.stat_rdr_activeEdges.add(activeEdgeMaxUsed);
   596             rdrCtx.stats.stat_rdr_activeEdges.add(activeEdgeMaxUsed);
   597             RendererContext.stats.stat_rdr_edges.add(edges.used);
   597             rdrCtx.stats.stat_rdr_edges.add(edges.used);
   598             RendererContext.stats.stat_rdr_edges_count
   598             rdrCtx.stats.stat_rdr_edges_count
   599                 .add(edges.used / SIZEOF_EDGE_BYTES);
   599                 .add(edges.used / SIZEOF_EDGE_BYTES);
   600         }
   600         }
   601         if (doCleanDirty) {
   601         if (DO_CLEAN_DIRTY) {
   602             // Force zero-fill dirty arrays:
   602             // Force zero-fill dirty arrays:
   603             Arrays.fill(crossings,     0);
   603             Arrays.fill(crossings,     0);
   604             Arrays.fill(aux_crossings, 0);
   604             Arrays.fill(aux_crossings, 0);
   605             Arrays.fill(edgePtrs,      0);
   605             Arrays.fill(edgePtrs,      0);
   606             Arrays.fill(aux_edgePtrs,  0);
   606             Arrays.fill(aux_edgePtrs,  0);
   668         // At last: resize back off-heap edges to initial size
   668         // At last: resize back off-heap edges to initial size
   669         if (edges.length != INITIAL_EDGES_CAPACITY) {
   669         if (edges.length != INITIAL_EDGES_CAPACITY) {
   670             // note: may throw OOME:
   670             // note: may throw OOME:
   671             edges.resize(INITIAL_EDGES_CAPACITY);
   671             edges.resize(INITIAL_EDGES_CAPACITY);
   672         }
   672         }
   673         if (doCleanDirty) {
   673         if (DO_CLEAN_DIRTY) {
   674             // Force zero-fill dirty arrays:
   674             // Force zero-fill dirty arrays:
   675             edges.fill(BYTE_0);
   675             edges.fill(BYTE_0);
   676         }
   676         }
   677         if (doMonitors) {
   677         if (DO_MONITORS) {
   678             RendererContext.stats.mon_rdr_endRendering.stop();
   678             rdrCtx.stats.mon_rdr_endRendering.stop();
   679         }
   679         }
   680     }
   680     }
   681 
   681 
   682     private static float tosubpixx(final float pix_x) {
   682     private static float tosubpixx(final float pix_x) {
   683         return f_SUBPIXEL_POSITIONS_X * pix_x;
   683         return f_SUBPIXEL_POSITIONS_X * pix_x;
   791 
   791 
   792         final int _ALL_BUT_LSB   = ALL_BUT_LSB;
   792         final int _ALL_BUT_LSB   = ALL_BUT_LSB;
   793         final int _ERR_STEP_MAX  = ERR_STEP_MAX;
   793         final int _ERR_STEP_MAX  = ERR_STEP_MAX;
   794 
   794 
   795         // unsafe I/O:
   795         // unsafe I/O:
   796         final Unsafe _unsafe = OffHeapArray.unsafe;
   796         final Unsafe _unsafe = OffHeapArray.UNSAFE;
   797         final long    addr0  = _edges.address;
   797         final long    addr0  = _edges.address;
   798         long addr;
   798         long addr;
   799         final int _SUBPIXEL_LG_POSITIONS_X = SUBPIXEL_LG_POSITIONS_X;
   799         final int _SUBPIXEL_LG_POSITIONS_X = SUBPIXEL_LG_POSITIONS_X;
   800         final int _SUBPIXEL_LG_POSITIONS_Y = SUBPIXEL_LG_POSITIONS_Y;
   800         final int _SUBPIXEL_LG_POSITIONS_Y = SUBPIXEL_LG_POSITIONS_Y;
   801         final int _SUBPIXEL_MASK_X = SUBPIXEL_MASK_X;
   801         final int _SUBPIXEL_MASK_X = SUBPIXEL_MASK_X;
   854             // marker on previously sorted edges:
   854             // marker on previously sorted edges:
   855             prevNumCrossings = numCrossings;
   855             prevNumCrossings = numCrossings;
   856 
   856 
   857             // bucketCount indicates new edge / edge end:
   857             // bucketCount indicates new edge / edge end:
   858             if (bucketcount != 0) {
   858             if (bucketcount != 0) {
   859                 if (doStats) {
   859                 if (DO_STATS) {
   860                     RendererContext.stats.stat_rdr_activeEdges_updates
   860                     rdrCtx.stats.stat_rdr_activeEdges_updates
   861                         .add(numCrossings);
   861                         .add(numCrossings);
   862                 }
   862                 }
   863 
   863 
   864                 // last bit set to 1 means that edges ends
   864                 // last bit set to 1 means that edges ends
   865                 if ((bucketcount & 0x1) != 0) {
   865                 if ((bucketcount & 0x1) != 0) {
   880                 }
   880                 }
   881 
   881 
   882                 ptrLen = bucketcount >> 1; // number of new edge
   882                 ptrLen = bucketcount >> 1; // number of new edge
   883 
   883 
   884                 if (ptrLen != 0) {
   884                 if (ptrLen != 0) {
   885                     if (doStats) {
   885                     if (DO_STATS) {
   886                         RendererContext.stats.stat_rdr_activeEdges_adds
   886                         rdrCtx.stats.stat_rdr_activeEdges_adds
   887                             .add(ptrLen);
   887                             .add(ptrLen);
   888                         if (ptrLen > 10) {
   888                         if (ptrLen > 10) {
   889                             RendererContext.stats.stat_rdr_activeEdges_adds_high
   889                             rdrCtx.stats.stat_rdr_activeEdges_adds_high
   890                                 .add(ptrLen);
   890                                 .add(ptrLen);
   891                         }
   891                         }
   892                     }
   892                     }
   893                     ptrEnd = numCrossings + ptrLen;
   893                     ptrEnd = numCrossings + ptrLen;
   894 
   894 
   895                     if (edgePtrsLen < ptrEnd) {
   895                     if (edgePtrsLen < ptrEnd) {
   896                         if (doStats) {
   896                         if (DO_STATS) {
   897                             RendererContext.stats.stat_array_renderer_edgePtrs
   897                             rdrCtx.stats.stat_array_renderer_edgePtrs
   898                                 .add(ptrEnd);
   898                                 .add(ptrEnd);
   899                         }
   899                         }
   900                         this.edgePtrs = _edgePtrs
   900                         this.edgePtrs = _edgePtrs
   901                             = rdrCtx.widenDirtyIntArray(_edgePtrs, numCrossings,
   901                             = rdrCtx.widenDirtyIntArray(_edgePtrs, numCrossings,
   902                                                         ptrEnd);
   902                                                         ptrEnd);
   906                         if (_aux_edgePtrs != aux_edgePtrs_initial) {
   906                         if (_aux_edgePtrs != aux_edgePtrs_initial) {
   907                             rdrCtx.putDirtyIntArray(_aux_edgePtrs);
   907                             rdrCtx.putDirtyIntArray(_aux_edgePtrs);
   908                         }
   908                         }
   909                         // use ArrayCache.getNewSize() to use the same growing
   909                         // use ArrayCache.getNewSize() to use the same growing
   910                         // factor than widenDirtyIntArray():
   910                         // factor than widenDirtyIntArray():
   911                         if (doStats) {
   911                         if (DO_STATS) {
   912                             RendererContext.stats.stat_array_renderer_aux_edgePtrs
   912                             rdrCtx.stats.stat_array_renderer_aux_edgePtrs
   913                                 .add(ptrEnd);
   913                                 .add(ptrEnd);
   914                         }
   914                         }
   915                         this.aux_edgePtrs = _aux_edgePtrs
   915                         this.aux_edgePtrs = _aux_edgePtrs
   916                             = rdrCtx.getDirtyIntArray(
   916                             = rdrCtx.getDirtyIntArray(
   917                                 ArrayCache.getNewSize(numCrossings, ptrEnd)
   917                                 ArrayCache.getNewSize(numCrossings, ptrEnd)
   934                     if (crossingsLen < numCrossings) {
   934                     if (crossingsLen < numCrossings) {
   935                         // Get larger array:
   935                         // Get larger array:
   936                         if (_crossings != crossings_initial) {
   936                         if (_crossings != crossings_initial) {
   937                             rdrCtx.putDirtyIntArray(_crossings);
   937                             rdrCtx.putDirtyIntArray(_crossings);
   938                         }
   938                         }
   939                         if (doStats) {
   939                         if (DO_STATS) {
   940                             RendererContext.stats.stat_array_renderer_crossings
   940                             rdrCtx.stats.stat_array_renderer_crossings
   941                                 .add(numCrossings);
   941                                 .add(numCrossings);
   942                         }
   942                         }
   943                         this.crossings = _crossings
   943                         this.crossings = _crossings
   944                             = rdrCtx.getDirtyIntArray(numCrossings);
   944                             = rdrCtx.getDirtyIntArray(numCrossings);
   945 
   945 
   946                         // Get larger auxiliary storage:
   946                         // Get larger auxiliary storage:
   947                         if (_aux_crossings != aux_crossings_initial) {
   947                         if (_aux_crossings != aux_crossings_initial) {
   948                             rdrCtx.putDirtyIntArray(_aux_crossings);
   948                             rdrCtx.putDirtyIntArray(_aux_crossings);
   949                         }
   949                         }
   950                         if (doStats) {
   950                         if (DO_STATS) {
   951                             RendererContext.stats.stat_array_renderer_aux_crossings
   951                             rdrCtx.stats.stat_array_renderer_aux_crossings
   952                                 .add(numCrossings);
   952                                 .add(numCrossings);
   953                         }
   953                         }
   954                         this.aux_crossings = _aux_crossings
   954                         this.aux_crossings = _aux_crossings
   955                             = rdrCtx.getDirtyIntArray(numCrossings);
   955                             = rdrCtx.getDirtyIntArray(numCrossings);
   956 
   956 
   957                         crossingsLen = _crossings.length;
   957                         crossingsLen = _crossings.length;
   958                     }
   958                     }
   959                     if (doStats) {
   959                     if (DO_STATS) {
   960                         // update max used mark
   960                         // update max used mark
   961                         if (numCrossings > _arrayMaxUsed) {
   961                         if (numCrossings > _arrayMaxUsed) {
   962                             _arrayMaxUsed = numCrossings;
   962                             _arrayMaxUsed = numCrossings;
   963                         }
   963                         }
   964                     }
   964                     }
   970                 /*
   970                 /*
   971                  * thresholds to switch to optimized merge sort
   971                  * thresholds to switch to optimized merge sort
   972                  * for newly added edges + final merge pass.
   972                  * for newly added edges + final merge pass.
   973                  */
   973                  */
   974                 if ((ptrLen < 10) || (numCrossings < 40)) {
   974                 if ((ptrLen < 10) || (numCrossings < 40)) {
   975                     if (doStats) {
   975                     if (DO_STATS) {
   976                         RendererContext.stats.hist_rdr_crossings
   976                         rdrCtx.stats.hist_rdr_crossings
   977                             .add(numCrossings);
   977                             .add(numCrossings);
   978                         RendererContext.stats.hist_rdr_crossings_adds
   978                         rdrCtx.stats.hist_rdr_crossings_adds
   979                             .add(ptrLen);
   979                             .add(ptrLen);
   980                     }
   980                     }
   981 
   981 
   982                     /*
   982                     /*
   983                      * threshold to use binary insertion sort instead of
   983                      * threshold to use binary insertion sort instead of
  1016                         // Manual carry handling:
  1016                         // Manual carry handling:
  1017                         // keep sign and carry bit only and ignore last bit (preserve orientation):
  1017                         // keep sign and carry bit only and ignore last bit (preserve orientation):
  1018                         _unsafe.putInt(addr,               curx - ((err >> 30) & _ALL_BUT_LSB));
  1018                         _unsafe.putInt(addr,               curx - ((err >> 30) & _ALL_BUT_LSB));
  1019                         _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
  1019                         _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
  1020 
  1020 
  1021                         if (doStats) {
  1021                         if (DO_STATS) {
  1022                             RendererContext.stats.stat_rdr_crossings_updates
  1022                             rdrCtx.stats.stat_rdr_crossings_updates
  1023                                 .add(numCrossings);
  1023                                 .add(numCrossings);
  1024                         }
  1024                         }
  1025 
  1025 
  1026                         // insertion sort of crossings:
  1026                         // insertion sort of crossings:
  1027                         if (cross < lastCross) {
  1027                         if (cross < lastCross) {
  1028                             if (doStats) {
  1028                             if (DO_STATS) {
  1029                                 RendererContext.stats.stat_rdr_crossings_sorts
  1029                                 rdrCtx.stats.stat_rdr_crossings_sorts
  1030                                     .add(i);
  1030                                     .add(i);
  1031                             }
  1031                             }
  1032 
  1032 
  1033                             /* use binary search for newly added edges
  1033                             /* use binary search for newly added edges
  1034                                in crossings if arrays are large enough */
  1034                                in crossings if arrays are large enough */
  1035                             if (useBinarySearch && (i >= prevNumCrossings)) {
  1035                             if (useBinarySearch && (i >= prevNumCrossings)) {
  1036                                 if (doStats) {
  1036                                 if (DO_STATS) {
  1037                                     RendererContext.stats.
  1037                                     rdrCtx.stats.
  1038                                         stat_rdr_crossings_bsearch.add(i);
  1038                                         stat_rdr_crossings_bsearch.add(i);
  1039                                 }
  1039                                 }
  1040                                 low = 0;
  1040                                 low = 0;
  1041                                 high = i - 1;
  1041                                 high = i - 1;
  1042 
  1042 
  1075                         } else {
  1075                         } else {
  1076                             _crossings[i] = lastCross = cross;
  1076                             _crossings[i] = lastCross = cross;
  1077                         }
  1077                         }
  1078                     }
  1078                     }
  1079                 } else {
  1079                 } else {
  1080                     if (doStats) {
  1080                     if (DO_STATS) {
  1081                         RendererContext.stats.stat_rdr_crossings_msorts
  1081                         rdrCtx.stats.stat_rdr_crossings_msorts
  1082                             .add(numCrossings);
  1082                             .add(numCrossings);
  1083                         RendererContext.stats.hist_rdr_crossings_ratio
  1083                         rdrCtx.stats.hist_rdr_crossings_ratio
  1084                             .add((1000 * ptrLen) / numCrossings);
  1084                             .add((1000 * ptrLen) / numCrossings);
  1085                         RendererContext.stats.hist_rdr_crossings_msorts
  1085                         rdrCtx.stats.hist_rdr_crossings_msorts
  1086                             .add(numCrossings);
  1086                             .add(numCrossings);
  1087                         RendererContext.stats.hist_rdr_crossings_msorts_adds
  1087                         rdrCtx.stats.hist_rdr_crossings_msorts_adds
  1088                             .add(ptrLen);
  1088                             .add(ptrLen);
  1089                     }
  1089                     }
  1090 
  1090 
  1091                     // Copy sorted data in auxiliary arrays
  1091                     // Copy sorted data in auxiliary arrays
  1092                     // and perform insertion sort on almost sorted data
  1092                     // and perform insertion sort on almost sorted data
  1122                         // Manual carry handling:
  1122                         // Manual carry handling:
  1123                         // keep sign and carry bit only and ignore last bit (preserve orientation):
  1123                         // keep sign and carry bit only and ignore last bit (preserve orientation):
  1124                         _unsafe.putInt(addr,               curx - ((err >> 30) & _ALL_BUT_LSB));
  1124                         _unsafe.putInt(addr,               curx - ((err >> 30) & _ALL_BUT_LSB));
  1125                         _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
  1125                         _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
  1126 
  1126 
  1127                         if (doStats) {
  1127                         if (DO_STATS) {
  1128                             RendererContext.stats.stat_rdr_crossings_updates
  1128                             rdrCtx.stats.stat_rdr_crossings_updates
  1129                                 .add(numCrossings);
  1129                                 .add(numCrossings);
  1130                         }
  1130                         }
  1131 
  1131 
  1132                         if (i >= prevNumCrossings) {
  1132                         if (i >= prevNumCrossings) {
  1133                             // simply store crossing as edgePtrs is in-place:
  1133                             // simply store crossing as edgePtrs is in-place:
  1134                             // will be copied and sorted efficiently by mergesort later:
  1134                             // will be copied and sorted efficiently by mergesort later:
  1135                             _crossings[i]     = cross;
  1135                             _crossings[i]     = cross;
  1136 
  1136 
  1137                         } else if (cross < lastCross) {
  1137                         } else if (cross < lastCross) {
  1138                             if (doStats) {
  1138                             if (DO_STATS) {
  1139                                 RendererContext.stats.stat_rdr_crossings_sorts
  1139                                 rdrCtx.stats.stat_rdr_crossings_sorts
  1140                                     .add(i);
  1140                                     .add(i);
  1141                             }
  1141                             }
  1142 
  1142 
  1143                             // (straight) insertion sort of crossings:
  1143                             // (straight) insertion sort of crossings:
  1144                             j = i - 1;
  1144                             j = i - 1;
  1354                         // => shift numCrossings by 1
  1354                         // => shift numCrossings by 1
  1355                         // condition = (width / (numCrossings - 1)) > blockSize
  1355                         // condition = (width / (numCrossings - 1)) > blockSize
  1356                         useBlkFlags = (maxX > _BLK_SIZE) && (maxX >
  1356                         useBlkFlags = (maxX > _BLK_SIZE) && (maxX >
  1357                             (((numCrossings >> stroking) - 1) << _BLK_SIZE_LG));
  1357                             (((numCrossings >> stroking) - 1) << _BLK_SIZE_LG));
  1358 
  1358 
  1359                         if (doStats) {
  1359                         if (DO_STATS) {
  1360                             tmp = FloatMath.max(1,
  1360                             tmp = FloatMath.max(1,
  1361                                     ((numCrossings >> stroking) - 1));
  1361                                     ((numCrossings >> stroking) - 1));
  1362                             RendererContext.stats.hist_tile_generator_encoding_dist
  1362                             rdrCtx.stats.hist_tile_generator_encoding_dist
  1363                                 .add(maxX / tmp);
  1363                                 .add(maxX / tmp);
  1364                         }
  1364                         }
  1365                     }
  1365                     }
  1366                 } else {
  1366                 } else {
  1367                     _cache.clearAARow(lastY);
  1367                     _cache.clearAARow(lastY);
  1390 
  1390 
  1391         // update member:
  1391         // update member:
  1392         edgeCount = numCrossings;
  1392         edgeCount = numCrossings;
  1393         prevUseBlkFlags = useBlkFlags;
  1393         prevUseBlkFlags = useBlkFlags;
  1394 
  1394 
  1395         if (doStats) {
  1395         if (DO_STATS) {
  1396             // update max used mark
  1396             // update max used mark
  1397             activeEdgeMaxUsed = _arrayMaxUsed;
  1397             activeEdgeMaxUsed = _arrayMaxUsed;
  1398         }
  1398         }
  1399     }
  1399     }
  1400 
  1400 
  1401     boolean endRendering() {
  1401     boolean endRendering() {
  1402         if (doMonitors) {
  1402         if (DO_MONITORS) {
  1403             RendererContext.stats.mon_rdr_endRendering.start();
  1403             rdrCtx.stats.mon_rdr_endRendering.start();
  1404         }
  1404         }
  1405         if (edgeMinY == Integer.MAX_VALUE) {
  1405         if (edgeMinY == Integer.MAX_VALUE) {
  1406             return false; // undefined edges bounds
  1406             return false; // undefined edges bounds
  1407         }
  1407         }
  1408 
  1408 
  1425             maxY   = _boundsMaxY;
  1425             maxY   = _boundsMaxY;
  1426         }
  1426         }
  1427         buckets_minY = spminY - _boundsMinY;
  1427         buckets_minY = spminY - _boundsMinY;
  1428         buckets_maxY = maxY   - _boundsMinY;
  1428         buckets_maxY = maxY   - _boundsMinY;
  1429 
  1429 
  1430         if (doLogBounds) {
  1430         if (DO_LOG_BOUNDS) {
  1431             MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
  1431             MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
  1432                                 + "][" + edgeMinY + " ... " + edgeMaxY + "]");
  1432                                 + "][" + edgeMinY + " ... " + edgeMaxY + "]");
  1433             MarlinUtils.logInfo("spXY    = [" + spminX + " ... " + spmaxX
  1433             MarlinUtils.logInfo("spXY    = [" + spminX + " ... " + spmaxX
  1434                                 + "][" + spminY + " ... " + spmaxY + "]");
  1434                                 + "][" + spminY + " ... " + spmaxY + "]");
  1435         }
  1435         }
  1477         // inclusive:
  1477         // inclusive:
  1478         bbox_spminY = spminY;
  1478         bbox_spminY = spminY;
  1479         // exclusive:
  1479         // exclusive:
  1480         bbox_spmaxY = FloatMath.min(spmaxY + 1, pmaxY << SUBPIXEL_LG_POSITIONS_Y);
  1480         bbox_spmaxY = FloatMath.min(spmaxY + 1, pmaxY << SUBPIXEL_LG_POSITIONS_Y);
  1481 
  1481 
  1482         if (doLogBounds) {
  1482         if (DO_LOG_BOUNDS) {
  1483             MarlinUtils.logInfo("pXY       = [" + pminX + " ... " + pmaxX
  1483             MarlinUtils.logInfo("pXY       = [" + pminX + " ... " + pmaxX
  1484                                 + "[ [" + pminY + " ... " + pmaxY + "[");
  1484                                 + "[ [" + pminY + " ... " + pmaxY + "[");
  1485             MarlinUtils.logInfo("bbox_spXY = [" + bbox_spminX + " ... "
  1485             MarlinUtils.logInfo("bbox_spXY = [" + bbox_spminX + " ... "
  1486                                 + bbox_spmaxX + "[ [" + bbox_spminY + " ... "
  1486                                 + bbox_spmaxX + "[ [" + bbox_spminY + " ... "
  1487                                 + bbox_spmaxY + "[");
  1487                                 + bbox_spmaxY + "[");
  1491         // add 2 to better deal with the last pixel in a pixel row.
  1491         // add 2 to better deal with the last pixel in a pixel row.
  1492         final int width = (pmaxX - pminX) + 2;
  1492         final int width = (pmaxX - pminX) + 2;
  1493 
  1493 
  1494         // Useful when processing tile line by tile line
  1494         // Useful when processing tile line by tile line
  1495         if (width > INITIAL_AA_ARRAY) {
  1495         if (width > INITIAL_AA_ARRAY) {
  1496             if (doStats) {
  1496             if (DO_STATS) {
  1497                 RendererContext.stats.stat_array_renderer_alphaline
  1497                 rdrCtx.stats.stat_array_renderer_alphaline
  1498                     .add(width);
  1498                     .add(width);
  1499             }
  1499             }
  1500             alphaLine = rdrCtx.getIntArray(width);
  1500             alphaLine = rdrCtx.getIntArray(width);
  1501         }
  1501         }
  1502 
  1502 
  1507     }
  1507     }
  1508 
  1508 
  1509     private int bbox_spminX, bbox_spmaxX, bbox_spminY, bbox_spmaxY;
  1509     private int bbox_spminX, bbox_spmaxX, bbox_spminY, bbox_spmaxY;
  1510 
  1510 
  1511     void endRendering(final int pminY) {
  1511     void endRendering(final int pminY) {
  1512         if (doMonitors) {
  1512         if (DO_MONITORS) {
  1513             RendererContext.stats.mon_rdr_endRendering_Y.start();
  1513             rdrCtx.stats.mon_rdr_endRendering_Y.start();
  1514         }
  1514         }
  1515 
  1515 
  1516         final int spminY       = pminY << SUBPIXEL_LG_POSITIONS_Y;
  1516         final int spminY       = pminY << SUBPIXEL_LG_POSITIONS_Y;
  1517         final int fixed_spminY = FloatMath.max(bbox_spminY, spminY);
  1517         final int fixed_spminY = FloatMath.max(bbox_spminY, spminY);
  1518 
  1518 
  1525             cache.resetTileLine(pminY);
  1525             cache.resetTileLine(pminY);
  1526 
  1526 
  1527             // Process only one tile line:
  1527             // Process only one tile line:
  1528             _endRendering(fixed_spminY, spmaxY);
  1528             _endRendering(fixed_spminY, spmaxY);
  1529         }
  1529         }
  1530         if (doMonitors) {
  1530         if (DO_MONITORS) {
  1531             RendererContext.stats.mon_rdr_endRendering_Y.stop();
  1531             rdrCtx.stats.mon_rdr_endRendering_Y.stop();
  1532         }
  1532         }
  1533     }
  1533     }
  1534 
  1534 
  1535     private boolean enableBlkFlags = false;
  1535     private boolean enableBlkFlags = false;
  1536     private boolean prevUseBlkFlags = false;
  1536     private boolean prevUseBlkFlags = false;
  1542     void copyAARow(final int[] alphaRow,
  1542     void copyAARow(final int[] alphaRow,
  1543                    final int pix_y, final int pix_from, final int pix_to,
  1543                    final int pix_y, final int pix_from, final int pix_to,
  1544                    final boolean useBlockFlags)
  1544                    final boolean useBlockFlags)
  1545     {
  1545     {
  1546         if (useBlockFlags) {
  1546         if (useBlockFlags) {
  1547             if (doStats) {
  1547             if (DO_STATS) {
  1548                 RendererContext.stats.hist_tile_generator_encoding.add(1);
  1548                 rdrCtx.stats.hist_tile_generator_encoding.add(1);
  1549             }
  1549             }
  1550             cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to);
  1550             cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to);
  1551         } else {
  1551         } else {
  1552             if (doStats) {
  1552             if (DO_STATS) {
  1553                 RendererContext.stats.hist_tile_generator_encoding.add(0);
  1553                 rdrCtx.stats.hist_tile_generator_encoding.add(0);
  1554             }
  1554             }
  1555             cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
  1555             cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
  1556         }
  1556         }
  1557     }
  1557     }
  1558 }
  1558 }