|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.java2d.marlin; |
|
|
|
import java.awt.geom.Path2D; |
|
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.MarlinRenderingEngine.NormalizingPathIterator; |
|
import static sun.java2d.marlin.MarlinUtils.logInfo; |
|
|
|
|
|
|
|
*/ |
|
final class RendererContext extends ReentrantContext implements MarlinConst { |
|
|
|
|
|
private static final AtomicInteger contextCount = new AtomicInteger(1); |
|
|
|
static final RendererStats stats = (doStats || doMonitors) |
|
? RendererStats.getInstance(): null; |
|
|
|
private static final boolean USE_CACHE_HARD_REF = doStats |
|
|| (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK); |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static RendererContext createContext() { |
|
final RendererContext newCtx = new RendererContext("ctx" |
|
+ Integer.toString(contextCount.getAndIncrement())); |
|
|
|
if (RendererContext.stats != null) { |
|
RendererContext.stats.allContexts.add(newCtx); |
|
} |
|
return newCtx; |
|
} |
|
|
|
|
|
final String name; |
|
|
|
boolean dirty = false; |
|
|
|
WeakReference<ArrayCachesHolder> refArrayCaches = null; |
|
|
|
ArrayCachesHolder hardRefArrayCaches = null; |
|
|
|
final float[] float6 = new float[6]; |
|
|
|
final Curve curve = new Curve(); |
|
|
|
final NormalizingPathIterator nPCPathIterator; |
|
|
|
final NormalizingPathIterator nPQPathIterator; |
|
|
|
final TransformingPathConsumer2D transformerPC2D; |
|
|
|
Path2D.Float p2d = null; |
|
final Renderer renderer; |
|
final Stroker stroker; |
|
|
|
final CollinearSimplifier simplifier = new CollinearSimplifier(); |
|
final Dasher dasher; |
|
final MarlinTileGenerator ptg; |
|
final MarlinCache cache; |
|
|
|
int stroking = 0; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
RendererContext(final String name) { |
|
if (logCreateContext) { |
|
MarlinUtils.logInfo("new RendererContext = " + name); |
|
} |
|
|
|
this.name = name; |
|
|
|
|
|
nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(float6); |
|
nPQPathIterator = new NormalizingPathIterator.NearestPixelQuarter(float6); |
|
|
|
|
|
transformerPC2D = new TransformingPathConsumer2D(); |
|
|
|
|
|
cache = new MarlinCache(this); |
|
renderer = new Renderer(this); |
|
ptg = new MarlinTileGenerator(renderer); |
|
|
|
stroker = new Stroker(this); |
|
dasher = new Dasher(this); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void dispose() { |
|
stroking = 0; |
|
|
|
if (!USE_CACHE_HARD_REF) { |
|
hardRefArrayCaches = null; |
|
} |
|
|
|
if (dirty) { |
|
// may happen if an exception if thrown in the pipeline processing: |
|
// force cleanup of all possible pipelined blocks (except Renderer): |
|
|
|
|
|
this.nPCPathIterator.dispose(); |
|
this.nPQPathIterator.dispose(); |
|
|
|
this.dasher.dispose(); |
|
|
|
this.stroker.dispose(); |
|
|
|
|
|
dirty = false; |
|
} |
|
} |
|
|
|
|
|
ArrayCachesHolder getArrayCachesHolder() { |
|
|
|
ArrayCachesHolder holder = hardRefArrayCaches; |
|
if (holder == null) { |
|
|
|
holder = (refArrayCaches != null) |
|
? refArrayCaches.get() |
|
: null; |
|
|
|
if (holder == null) { |
|
if (logCreateContext) { |
|
MarlinUtils.logInfo("new ArrayCachesHolder for " |
|
+ "RendererContext = " + name); |
|
} |
|
|
|
holder = new ArrayCachesHolder(); |
|
|
|
if (USE_CACHE_HARD_REF) { |
|
|
|
hardRefArrayCaches = holder; |
|
} |
|
|
|
|
|
refArrayCaches = new WeakReference<ArrayCachesHolder>(holder); |
|
} |
|
} |
|
return holder; |
|
} |
|
|
|
|
|
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 (doStats) { |
|
incOversize(); |
|
} |
|
|
|
if (doLogOverSize) { |
|
logInfo("getDirtyByteArray[oversize]: length=\t" + length); |
|
} |
|
|
|
return new byte[length]; |
|
} |
|
|
|
void putDirtyByteArray(final byte[] array) { |
|
final int length = array.length; |
|
// odd sized array are non-cached arrays (initial arrays) |
|
|
|
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 (doChecks && length >= needSize) { |
|
return in; |
|
} |
|
if (doStats) { |
|
incResizeDirtyByte(); |
|
} |
|
|
|
// maybe change bucket: |
|
|
|
final byte[] res = getDirtyByteArray(getNewSize(usedSize, needSize)); |
|
|
|
System.arraycopy(in, 0, res, 0, usedSize); |
|
|
|
// maybe return current array: |
|
|
|
putDirtyByteArray(in); |
|
|
|
if (doLogWidenArray) { |
|
logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t" |
|
+ usedSize + "\tlength=\t" + length + "\tneeded length=\t" |
|
+ needSize); |
|
} |
|
return res; |
|
} |
|
|
|
|
|
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 (doStats) { |
|
incOversize(); |
|
} |
|
|
|
if (doLogOverSize) { |
|
logInfo("getIntArray[oversize]: length=\t" + length); |
|
} |
|
|
|
return new int[length]; |
|
} |
|
|
|
|
|
int[] widenIntArray(final int[] in, final int usedSize, |
|
final int needSize, final int clearTo) |
|
{ |
|
final int length = in.length; |
|
if (doChecks && length >= needSize) { |
|
return in; |
|
} |
|
if (doStats) { |
|
incResizeInt(); |
|
} |
|
|
|
// maybe change bucket: |
|
|
|
final int[] res = getIntArray(getNewSize(usedSize, needSize)); |
|
|
|
System.arraycopy(in, 0, res, 0, usedSize); |
|
|
|
// maybe return current array: |
|
putIntArray(in, 0, clearTo); |
|
|
|
if (doLogWidenArray) { |
|
logInfo("widenIntArray[" + res.length + "]: usedSize=\t" |
|
+ usedSize + "\tlength=\t" + length + "\tneeded length=\t" |
|
+ needSize); |
|
} |
|
return res; |
|
} |
|
|
|
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) |
|
|
|
if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) { |
|
getIntArrayCache(length).putArray(array, length, fromIndex, toIndex); |
|
} |
|
} |
|
|
|
|
|
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 (doStats) { |
|
incOversize(); |
|
} |
|
|
|
if (doLogOverSize) { |
|
logInfo("getDirtyIntArray[oversize]: length=\t" + length); |
|
} |
|
|
|
return new int[length]; |
|
} |
|
|
|
int[] widenDirtyIntArray(final int[] in, |
|
final int usedSize, final int needSize) |
|
{ |
|
final int length = in.length; |
|
if (doChecks && length >= needSize) { |
|
return in; |
|
} |
|
if (doStats) { |
|
incResizeDirtyInt(); |
|
} |
|
|
|
// maybe change bucket: |
|
|
|
final int[] res = getDirtyIntArray(getNewSize(usedSize, needSize)); |
|
|
|
System.arraycopy(in, 0, res, 0, usedSize); |
|
|
|
// maybe return current array: |
|
|
|
putDirtyIntArray(in); |
|
|
|
if (doLogWidenArray) { |
|
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) |
|
|
|
if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) { |
|
getDirtyIntArrayCache(length).putDirtyArray(array, length); |
|
} |
|
} |
|
|
|
|
|
FloatArrayCache getDirtyFloatArrayCache(final int length) { |
|
final int bucket = ArrayCache.getBucket(length); |
|
return getArrayCachesHolder().dirtyFloatArrayCaches[bucket]; |
|
} |
|
|
|
float[] getDirtyFloatArray(final int length) { |
|
if (length <= MAX_ARRAY_SIZE) { |
|
return getDirtyFloatArrayCache(length).getArray(); |
|
} |
|
|
|
if (doStats) { |
|
incOversize(); |
|
} |
|
|
|
if (doLogOverSize) { |
|
logInfo("getDirtyFloatArray[oversize]: length=\t" + length); |
|
} |
|
|
|
return new float[length]; |
|
} |
|
|
|
float[] widenDirtyFloatArray(final float[] in, |
|
final int usedSize, final int needSize) |
|
{ |
|
final int length = in.length; |
|
if (doChecks && length >= needSize) { |
|
return in; |
|
} |
|
if (doStats) { |
|
incResizeDirtyFloat(); |
|
} |
|
|
|
// maybe change bucket: |
|
|
|
final float[] res = getDirtyFloatArray(getNewSize(usedSize, needSize)); |
|
|
|
System.arraycopy(in, 0, res, 0, usedSize); |
|
|
|
// maybe return current array: |
|
|
|
putDirtyFloatArray(in); |
|
|
|
if (doLogWidenArray) { |
|
logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t" |
|
+ usedSize + "\tlength=\t" + length + "\tneeded length=\t" |
|
+ needSize); |
|
} |
|
return res; |
|
} |
|
|
|
void putDirtyFloatArray(final float[] array) { |
|
final int length = array.length; |
|
// odd sized array are non-cached arrays (initial arrays) |
|
|
|
if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) { |
|
getDirtyFloatArrayCache(length).putDirtyArray(array, length); |
|
} |
|
} |
|
|
|
|
|
static final class ArrayCachesHolder { |
|
|
|
final IntArrayCache[] intArrayCaches; |
|
|
|
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]); |
|
|
|
dirtyIntArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]); |
|
dirtyFloatArrayCaches[i] = new FloatArrayCache(ARRAY_SIZES[i]); |
|
dirtyByteArrayCaches[i] = new ByteArrayCache(DIRTY_BYTE_ARRAY_SIZES[i]); |
|
} |
|
} |
|
} |
|
} |