8159638: Improve array caches and renderer stats in Marlin renderer
Summary: Byte/Float/Int ArrayCache (Reference) refactoring + improved cache statistics and tuning settings
Reviewed-by: flar, prr
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
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.marlin.ArrayCacheConst.CacheStats;
import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator;
/**
* This class is a renderer context dedicated to a single thread
*/
final class RendererContext extends ReentrantContext implements MarlinConst {
// RendererContext creation counter
private static final AtomicInteger CTX_COUNT = new AtomicInteger(1);
/**
* Create a new renderer context
*
* @return new RendererContext instance
*/
static RendererContext createContext() {
return new RendererContext("ctx"
+ Integer.toString(CTX_COUNT.getAndIncrement()));
}
// Smallest object used as Cleaner's parent reference
private final Object cleanerObj;
// dirty flag indicating an exception occured during pipeline in pathTo()
boolean dirty = false;
// shared data
final float[] float6 = new float[6];
// shared curve (dirty) (Renderer / Stroker)
final Curve curve = new Curve();
// MarlinRenderingEngine NormalizingPathIterator NearestPixelCenter:
final NormalizingPathIterator nPCPathIterator;
// MarlinRenderingEngine NearestPixelQuarter NormalizingPathIterator:
final NormalizingPathIterator nPQPathIterator;
// MarlinRenderingEngine.TransformingPathConsumer2D
final TransformingPathConsumer2D transformerPC2D;
// recycled Path2D instance (weak)
private WeakReference<Path2D.Float> refPath2D = null;
final Renderer renderer;
final Stroker stroker;
// Simplifies out collinear lines
final CollinearSimplifier simplifier = new CollinearSimplifier();
final Dasher dasher;
final MarlinTileGenerator ptg;
final MarlinCache cache;
// 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
*
* @param name context name (debugging)
*/
RendererContext(final String name) {
if (LOG_CREATE_CONTEXT) {
MarlinUtils.logInfo("new RendererContext = " + name);
}
this.cleanerObj = new Object();
// 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);
nPQPathIterator = new NormalizingPathIterator.NearestPixelQuarter(float6);
// MarlinRenderingEngine.TransformingPathConsumer2D
transformerPC2D = new TransformingPathConsumer2D();
// Renderer:
cache = new MarlinCache(this);
renderer = new Renderer(this); // needs MarlinCache from rdrCtx.cache
ptg = new MarlinTileGenerator(renderer);
stroker = new Stroker(this);
dasher = new Dasher(this);
}
/**
* Disposes this renderer context:
* 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;
// if context is maked as DIRTY:
if (dirty) {
// may happen if an exception if thrown in the pipeline processing:
// force cleanup of all possible pipelined blocks (except Renderer):
// NormalizingPathIterator instances:
this.nPCPathIterator.dispose();
this.nPQPathIterator.dispose();
// Dasher:
this.dasher.dispose();
// Stroker:
this.stroker.dispose();
// mark context as CLEAN:
dirty = false;
}
}
Path2D.Float getPath2D() {
// resolve reference:
Path2D.Float p2d
= (refPath2D != null) ? refPath2D.get() : null;
// create a new Path2D ?
if (p2d == null) {
p2d = new Path2D.Float(Path2D.WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K
// update weak reference:
refPath2D = new WeakReference<Path2D.Float>(p2d);
}
// reset the path anyway:
p2d.reset();
return p2d;
}
OffHeapArray newOffHeapArray(final long initialSize) {
if (DO_STATS) {
stats.totalOffHeapInitial += initialSize;
}
return new OffHeapArray(cleanerObj, initialSize);
}
IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) {
return cleanIntCache.createRef(initialSize);
}
IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) {
return dirtyIntCache.createRef(initialSize);
}
FloatArrayCache.Reference newDirtyFloatArrayRef(final int initialSize) {
return dirtyFloatCache.createRef(initialSize);
}
ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) {
return dirtyByteCache.createRef(initialSize);
}
}