--- /dev/null 2017-05-09 09:58:57.635126128 +0200 +++ new/src/java.desktop/share/classes/sun/java2d/marlin/DRendererContext.java 2017-05-09 10:56:16.299279933 +0200 @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2015, 2017, 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.DMarlinRenderingEngine.NormalizingPathIterator; + +/** + * This class is a renderer context dedicated to a single thread + */ +final class DRendererContext extends ReentrantContext implements IRendererContext { + + // RendererContext creation counter + private static final AtomicInteger CTX_COUNT = new AtomicInteger(1); + + /** + * Create a new renderer context + * + * @return new RendererContext instance + */ + static DRendererContext createContext() { + return new DRendererContext("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 double[] double6 = new double[6]; + // shared curve (dirty) (Renderer / Stroker) + final DCurve curve = new DCurve(); + // MarlinRenderingEngine NormalizingPathIterator NearestPixelCenter: + final NormalizingPathIterator nPCPathIterator; + // MarlinRenderingEngine NearestPixelQuarter NormalizingPathIterator: + final NormalizingPathIterator nPQPathIterator; + // MarlinRenderingEngine.TransformingPathConsumer2D + final DTransformingPathConsumer2D transformerPC2D; + // recycled Path2D instance (weak) + private WeakReference refPath2D = null; + final DRenderer renderer; + final DStroker stroker; + // Simplifies out collinear lines + final DCollinearSimplifier simplifier = new DCollinearSimplifier(); + final DDasher 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 double[] cache = 3 refs */ + private final DoubleArrayCache dirtyDoubleCache = new DoubleArrayCache(false, 3); + /* dirty byte[] cache = 1 ref */ + private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 1); + + // RendererContext statistics + final RendererStats stats; + + final PathConsumer2DAdapter p2dAdapter = new PathConsumer2DAdapter(); + + + /** + * Constructor + * + * @param name context name (debugging) + */ + DRendererContext(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, dirtyDoubleCache.stats, dirtyByteCache.stats + }; + } else { + stats = null; + } + + // NormalizingPathIterator instances: + nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(double6); + nPQPathIterator = new NormalizingPathIterator.NearestPixelQuarter(double6); + + // MarlinRenderingEngine.TransformingPathConsumer2D + transformerPC2D = new DTransformingPathConsumer2D(); + + // Renderer: + cache = new MarlinCache(this); + renderer = new DRenderer(this); // needs MarlinCache from rdrCtx.cache + ptg = new MarlinTileGenerator(stats, renderer, cache); + + stroker = new DStroker(this); + dasher = new DDasher(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.Double getPath2D() { + // resolve reference: + Path2D.Double p2d + = (refPath2D != null) ? refPath2D.get() : null; + + // create a new Path2D ? + if (p2d == null) { + p2d = new Path2D.Double(Path2D.WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K + + // update weak reference: + refPath2D = new WeakReference(p2d); + } + // reset the path anyway: + p2d.reset(); + return p2d; + } + + @Override + public RendererStats stats() { + return stats; + } + + @Override + public OffHeapArray newOffHeapArray(final long initialSize) { + if (DO_STATS) { + stats.totalOffHeapInitial += initialSize; + } + return new OffHeapArray(cleanerObj, initialSize); + } + + @Override + public IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) { + return cleanIntCache.createRef(initialSize); + } + + IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) { + return dirtyIntCache.createRef(initialSize); + } + + DoubleArrayCache.Reference newDirtyDoubleArrayRef(final int initialSize) { + return dirtyDoubleCache.createRef(initialSize); + } + + ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) { + return dirtyByteCache.createRef(initialSize); + } + + static final class PathConsumer2DAdapter implements DPathConsumer2D { + private sun.awt.geom.PathConsumer2D out; + + PathConsumer2DAdapter() {} + + PathConsumer2DAdapter init(sun.awt.geom.PathConsumer2D out) { + this.out = out; + return this; + } + + @Override + public void moveTo(double x0, double y0) { + out.moveTo((float)x0, (float)y0); + } + + @Override + public void lineTo(double x1, double y1) { + out.lineTo((float)x1, (float)y1); + } + + @Override + public void closePath() { + out.closePath(); + } + + @Override + public void pathDone() { + out.pathDone(); + } + + @Override + public void curveTo(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + out.curveTo((float)x1, (float)y1, + (float)x2, (float)y2, + (float)x3, (float)y3); + } + + @Override + public void quadTo(double x1, double y1, double x2, double y2) { + out.quadTo((float)x1, (float)y1, (float)x2, (float)y2); + } + + @Override + public long getNativeConsumer() { + throw new InternalError("Not using a native peer"); + } + } +}