--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java Wed Aug 03 14:49:01 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java Wed Aug 03 22:53:38 2016 +0200
@@ -29,10 +29,8 @@
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicInteger;
import sun.java2d.ReentrantContext;
-import sun.java2d.ReentrantContextProvider;
-import static sun.java2d.marlin.ArrayCache.*;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator;
-import static sun.java2d.marlin.MarlinUtils.logInfo;
/**
* This class is a renderer context dedicated to a single thread
@@ -41,12 +39,6 @@
// RendererContext creation counter
private static final AtomicInteger CTX_COUNT = new AtomicInteger(1);
- // RendererContext statistics
- final RendererStats stats = (DO_STATS || DO_MONITORS)
- ? RendererStats.getInstance(): null;
-
- private static final boolean USE_CACHE_HARD_REF = DO_STATS
- || (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK);
/**
* Create a new renderer context
@@ -54,25 +46,14 @@
* @return new RendererContext instance
*/
static RendererContext createContext() {
- final RendererContext newCtx = new RendererContext("ctx"
- + Integer.toString(CTX_COUNT.getAndIncrement()));
-
- if (DO_STATS || DO_MONITORS) {
- RendererStats.ALL_CONTEXTS.add(newCtx);
- }
- return newCtx;
+ return new RendererContext("ctx"
+ + Integer.toString(CTX_COUNT.getAndIncrement()));
}
- // context name (debugging purposes)
- final String name;
// Smallest object used as Cleaner's parent reference
- final Object cleanerObj = new Object();
+ private final Object cleanerObj;
// dirty flag indicating an exception occured during pipeline in pathTo()
boolean dirty = false;
- // dynamic array caches kept using weak reference (low memory footprint)
- WeakReference<ArrayCachesHolder> refArrayCaches = null;
- // hard reference to array caches (for statistics)
- ArrayCachesHolder hardRefArrayCaches = null;
// shared data
final float[] float6 = new float[6];
// shared curve (dirty) (Renderer / Stroker)
@@ -83,8 +64,8 @@
final NormalizingPathIterator nPQPathIterator;
// MarlinRenderingEngine.TransformingPathConsumer2D
final TransformingPathConsumer2D transformerPC2D;
- // recycled Path2D instance
- Path2D.Float p2d = null;
+ // recycled Path2D instance (weak)
+ private WeakReference<Path2D.Float> refPath2D = null;
final Renderer renderer;
final Stroker stroker;
// Simplifies out collinear lines
@@ -95,6 +76,19 @@
// flag indicating the shape is stroked (1) or filled (0)
int stroking = 0;
+ // Array caches:
+ /* clean int[] cache (zero-filled) = 5 refs */
+ private final IntArrayCache cleanIntCache = new IntArrayCache(true, 5);
+ /* dirty int[] cache = 4 refs */
+ private final IntArrayCache dirtyIntCache = new IntArrayCache(false, 4);
+ /* dirty float[] cache = 3 refs */
+ private final FloatArrayCache dirtyFloatCache = new FloatArrayCache(false, 3);
+ /* dirty byte[] cache = 1 ref */
+ private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 1);
+
+ // RendererContext statistics
+ final RendererStats stats;
+
/**
* Constructor
*
@@ -104,8 +98,18 @@
if (LOG_CREATE_CONTEXT) {
MarlinUtils.logInfo("new RendererContext = " + name);
}
+ this.cleanerObj = new Object();
- this.name = name;
+ // create first stats (needed by newOffHeapArray):
+ if (DO_STATS || DO_MONITORS) {
+ stats = RendererStats.createInstance(cleanerObj, name);
+ // push cache stats:
+ stats.cacheStats = new CacheStats[] { cleanIntCache.stats,
+ dirtyIntCache.stats, dirtyFloatCache.stats, dirtyByteCache.stats
+ };
+ } else {
+ stats = null;
+ }
// NormalizingPathIterator instances:
nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(float6);
@@ -128,11 +132,13 @@
* clean up before reusing this context
*/
void dispose() {
+ if (DO_STATS) {
+ if (stats.totalOffHeap > stats.totalOffHeapMax) {
+ stats.totalOffHeapMax = stats.totalOffHeap;
+ }
+ stats.totalOffHeap = 0L;
+ }
stroking = 0;
- // reset hard reference to array caches if needed:
- if (!USE_CACHE_HARD_REF) {
- hardRefArrayCaches = null;
- }
// if context is maked as DIRTY:
if (dirty) {
// may happen if an exception if thrown in the pipeline processing:
@@ -151,300 +157,43 @@
}
}
- // Array caches
- ArrayCachesHolder getArrayCachesHolder() {
- // Use hard reference first (cached resolved weak reference):
- ArrayCachesHolder holder = hardRefArrayCaches;
- if (holder == null) {
- // resolve reference:
- holder = (refArrayCaches != null)
- ? refArrayCaches.get()
- : null;
- // create a new ArrayCachesHolder if none is available
- if (holder == null) {
- if (LOG_CREATE_CONTEXT) {
- MarlinUtils.logInfo("new ArrayCachesHolder for "
- + "RendererContext = " + name);
- }
-
- holder = new ArrayCachesHolder();
-
- if (USE_CACHE_HARD_REF) {
- // update hard reference:
- hardRefArrayCaches = holder;
- } else {
- // update weak reference:
- refArrayCaches = new WeakReference<ArrayCachesHolder>(holder);
- }
- }
- }
- return holder;
- }
+ Path2D.Float getPath2D() {
+ // resolve reference:
+ Path2D.Float p2d
+ = (refPath2D != null) ? refPath2D.get() : null;
- // dirty byte array cache
- ByteArrayCache getDirtyByteArrayCache(final int length) {
- final int bucket = ArrayCache.getBucketDirtyBytes(length);
- return getArrayCachesHolder().dirtyByteArrayCaches[bucket];
- }
-
- byte[] getDirtyByteArray(final int length) {
- if (length <= MAX_DIRTY_BYTE_ARRAY_SIZE) {
- return getDirtyByteArrayCache(length).getArray();
- }
-
- if (DO_STATS) {
- incOversize();
- }
-
- if (DO_LOG_OVERSIZE) {
- logInfo("getDirtyByteArray[oversize]: length=\t" + length);
- }
+ // create a new Path2D ?
+ if (p2d == null) {
+ p2d = new Path2D.Float(Path2D.WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K
- return new byte[length];
- }
-
- void putDirtyByteArray(final byte[] array) {
- final int length = array.length;
- // odd sized array are non-cached arrays (initial arrays)
- // ensure to never store initial arrays in cache:
- if (((length & 0x1) == 0) && (length <= MAX_DIRTY_BYTE_ARRAY_SIZE)) {
- getDirtyByteArrayCache(length).putDirtyArray(array, length);
- }
- }
-
- byte[] widenDirtyByteArray(final byte[] in,
- final int usedSize, final int needSize)
- {
- final int length = in.length;
- if (DO_CHECKS && length >= needSize) {
- return in;
+ // update weak reference:
+ refPath2D = new WeakReference<Path2D.Float>(p2d);
}
- if (DO_STATS) {
- incResizeDirtyByte();
- }
-
- // maybe change bucket:
- // ensure getNewSize() > newSize:
- final byte[] res = getDirtyByteArray(getNewSize(usedSize, needSize));
-
- System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
- // maybe return current array:
- // NO clean-up of array data = DIRTY ARRAY
- putDirtyByteArray(in);
-
- if (DO_LOG_WIDEN_ARRAY) {
- logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t"
- + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
- + needSize);
- }
- return res;
- }
-
- // int array cache
- IntArrayCache getIntArrayCache(final int length) {
- final int bucket = ArrayCache.getBucket(length);
- return getArrayCachesHolder().intArrayCaches[bucket];
- }
-
- int[] getIntArray(final int length) {
- if (length <= MAX_ARRAY_SIZE) {
- return getIntArrayCache(length).getArray();
- }
-
- if (DO_STATS) {
- incOversize();
- }
-
- if (DO_LOG_OVERSIZE) {
- logInfo("getIntArray[oversize]: length=\t" + length);
- }
-
- return new int[length];
- }
-
- // unused
- int[] widenIntArray(final int[] in, final int usedSize,
- final int needSize, final int clearTo)
- {
- final int length = in.length;
- if (DO_CHECKS && length >= needSize) {
- return in;
- }
- if (DO_STATS) {
- incResizeInt();
- }
-
- // maybe change bucket:
- // ensure getNewSize() > newSize:
- final int[] res = getIntArray(getNewSize(usedSize, needSize));
-
- System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
- // maybe return current array:
- putIntArray(in, 0, clearTo); // ensure all array is cleared (grow-reduce algo)
-
- if (DO_LOG_WIDEN_ARRAY) {
- logInfo("widenIntArray[" + res.length + "]: usedSize=\t"
- + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
- + needSize);
- }
- return res;
+ // reset the path anyway:
+ p2d.reset();
+ return p2d;
}
- void putIntArray(final int[] array, final int fromIndex,
- final int toIndex)
- {
- final int length = array.length;
- // odd sized array are non-cached arrays (initial arrays)
- // ensure to never store initial arrays in cache:
- if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
- getIntArrayCache(length).putArray(array, length, fromIndex, toIndex);
+ OffHeapArray newOffHeapArray(final long initialSize) {
+ if (DO_STATS) {
+ stats.totalOffHeapInitial += initialSize;
}
- }
-
- // dirty int array cache
- IntArrayCache getDirtyIntArrayCache(final int length) {
- final int bucket = ArrayCache.getBucket(length);
- return getArrayCachesHolder().dirtyIntArrayCaches[bucket];
- }
-
- int[] getDirtyIntArray(final int length) {
- if (length <= MAX_ARRAY_SIZE) {
- return getDirtyIntArrayCache(length).getArray();
- }
-
- if (DO_STATS) {
- incOversize();
- }
-
- if (DO_LOG_OVERSIZE) {
- logInfo("getDirtyIntArray[oversize]: length=\t" + length);
- }
-
- return new int[length];
+ return new OffHeapArray(cleanerObj, initialSize);
}
- int[] widenDirtyIntArray(final int[] in,
- final int usedSize, final int needSize)
- {
- final int length = in.length;
- if (DO_CHECKS && length >= needSize) {
- return in;
- }
- if (DO_STATS) {
- incResizeDirtyInt();
- }
-
- // maybe change bucket:
- // ensure getNewSize() > newSize:
- final int[] res = getDirtyIntArray(getNewSize(usedSize, needSize));
-
- System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
- // maybe return current array:
- // NO clean-up of array data = DIRTY ARRAY
- putDirtyIntArray(in);
-
- if (DO_LOG_WIDEN_ARRAY) {
- logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t"
- + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
- + needSize);
- }
- return res;
- }
-
- void putDirtyIntArray(final int[] array) {
- final int length = array.length;
- // odd sized array are non-cached arrays (initial arrays)
- // ensure to never store initial arrays in cache:
- if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
- getDirtyIntArrayCache(length).putDirtyArray(array, length);
- }
- }
-
- // dirty float array cache
- FloatArrayCache getDirtyFloatArrayCache(final int length) {
- final int bucket = ArrayCache.getBucket(length);
- return getArrayCachesHolder().dirtyFloatArrayCaches[bucket];
+ IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) {
+ return cleanIntCache.createRef(initialSize);
}
- float[] getDirtyFloatArray(final int length) {
- if (length <= MAX_ARRAY_SIZE) {
- return getDirtyFloatArrayCache(length).getArray();
- }
-
- if (DO_STATS) {
- incOversize();
- }
-
- if (DO_LOG_OVERSIZE) {
- logInfo("getDirtyFloatArray[oversize]: length=\t" + length);
- }
-
- return new float[length];
+ IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) {
+ return dirtyIntCache.createRef(initialSize);
}
- float[] widenDirtyFloatArray(final float[] in,
- final int usedSize, final int needSize)
- {
- final int length = in.length;
- if (DO_CHECKS && length >= needSize) {
- return in;
- }
- if (DO_STATS) {
- incResizeDirtyFloat();
- }
-
- // maybe change bucket:
- // ensure getNewSize() > newSize:
- final float[] res = getDirtyFloatArray(getNewSize(usedSize, needSize));
-
- System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
- // maybe return current array:
- // NO clean-up of array data = DIRTY ARRAY
- putDirtyFloatArray(in);
-
- if (DO_LOG_WIDEN_ARRAY) {
- logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t"
- + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
- + needSize);
- }
- return res;
+ FloatArrayCache.Reference newDirtyFloatArrayRef(final int initialSize) {
+ return dirtyFloatCache.createRef(initialSize);
}
- void putDirtyFloatArray(final float[] array) {
- final int length = array.length;
- // odd sized array are non-cached arrays (initial arrays)
- // ensure to never store initial arrays in cache:
- if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
- getDirtyFloatArrayCache(length).putDirtyArray(array, length);
- }
- }
-
- /* class holding all array cache instances */
- static final class ArrayCachesHolder {
- // zero-filled int array cache:
- final IntArrayCache[] intArrayCaches;
- // dirty array caches:
- final IntArrayCache[] dirtyIntArrayCaches;
- final FloatArrayCache[] dirtyFloatArrayCaches;
- final ByteArrayCache[] dirtyByteArrayCaches;
-
- ArrayCachesHolder() {
- intArrayCaches = new IntArrayCache[BUCKETS];
- dirtyIntArrayCaches = new IntArrayCache[BUCKETS];
- dirtyFloatArrayCaches = new FloatArrayCache[BUCKETS];
- dirtyByteArrayCaches = new ByteArrayCache[BUCKETS];
-
- for (int i = 0; i < BUCKETS; i++) {
- intArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);
- // dirty array caches:
- dirtyIntArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);
- dirtyFloatArrayCaches[i] = new FloatArrayCache(ARRAY_SIZES[i]);
- dirtyByteArrayCaches[i] = new ByteArrayCache(DIRTY_BYTE_ARRAY_SIZES[i]);
- }
- }
+ ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) {
+ return dirtyByteCache.createRef(initialSize);
}
}