1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.java2d.marlin; 27 28 import java.awt.Rectangle; 29 import java.awt.geom.Path2D; 30 import java.lang.ref.WeakReference; 31 import java.util.concurrent.atomic.AtomicInteger; 32 import sun.java2d.ReentrantContext; 33 import sun.java2d.marlin.ArrayCacheConst.CacheStats; 34 import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator; 35 36 /** 37 * This class is a renderer context dedicated to a single thread 38 */ 39 final class RendererContext extends ReentrantContext implements IRendererContext { 40 41 // RendererContext creation counter 42 private static final AtomicInteger CTX_COUNT = new AtomicInteger(1); 43 44 /** 45 * Create a new renderer context 46 * 47 * @return new RendererContext instance 48 */ 49 static RendererContext createContext() { 50 return new RendererContext("ctx" 51 + Integer.toString(CTX_COUNT.getAndIncrement())); 52 } 53 54 // Smallest object used as Cleaner's parent reference 55 private final Object cleanerObj; 56 // dirty flag indicating an exception occured during pipeline in pathTo() 57 boolean dirty = false; 58 // shared data 59 final float[] float6 = new float[6]; 60 // shared curve (dirty) (Renderer / Stroker) 61 final Curve curve = new Curve(); 62 // MarlinRenderingEngine NormalizingPathIterator NearestPixelCenter: 63 final NormalizingPathIterator nPCPathIterator; 64 // MarlinRenderingEngine NearestPixelQuarter NormalizingPathIterator: 65 final NormalizingPathIterator nPQPathIterator; 66 // MarlinRenderingEngine.TransformingPathConsumer2D 67 final TransformingPathConsumer2D transformerPC2D; 68 // recycled Path2D instance (weak) 69 private WeakReference<Path2D.Float> refPath2D = null; 70 final Renderer renderer; 71 final Stroker stroker; 72 // Simplifies out collinear lines 73 final CollinearSimplifier simplifier = new CollinearSimplifier(); 74 final Dasher dasher; 75 final MarlinTileGenerator ptg; 76 final MarlinCache cache; 77 // flag indicating the shape is stroked (1) or filled (0) 78 int stroking = 0; 79 // flag indicating to clip the shape 80 boolean doClip = false; 81 // flag indicating if the path is closed or not (in advance) to handle properly caps 82 boolean closedPath = false; 83 // clip rectangle (ymin, ymax, xmin, xmax): 84 final float[] clipRect = new float[4]; 85 86 // Array caches: 87 /* clean int[] cache (zero-filled) = 5 refs */ 88 private final IntArrayCache cleanIntCache = new IntArrayCache(true, 5); 89 /* dirty int[] cache = 4 refs */ 90 private final IntArrayCache dirtyIntCache = new IntArrayCache(false, 4); 91 /* dirty float[] cache = 3 refs */ 92 private final FloatArrayCache dirtyFloatCache = new FloatArrayCache(false, 3); 93 /* dirty byte[] cache = 1 ref */ 94 private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 1); 95 96 // RendererContext statistics 97 final RendererStats stats; 98 99 /** 100 * Constructor 101 * 102 * @param name context name (debugging) 103 */ 104 RendererContext(final String name) { 105 if (LOG_CREATE_CONTEXT) { 106 MarlinUtils.logInfo("new RendererContext = " + name); 107 } 108 this.cleanerObj = new Object(); 109 110 // create first stats (needed by newOffHeapArray): 111 if (DO_STATS || DO_MONITORS) { 112 stats = RendererStats.createInstance(cleanerObj, name); 113 // push cache stats: 114 stats.cacheStats = new CacheStats[] { cleanIntCache.stats, 115 dirtyIntCache.stats, dirtyFloatCache.stats, dirtyByteCache.stats 116 }; 117 } else { 118 stats = null; 119 } 120 121 // NormalizingPathIterator instances: 122 nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(float6); 123 nPQPathIterator = new NormalizingPathIterator.NearestPixelQuarter(float6); 124 125 // MarlinRenderingEngine.TransformingPathConsumer2D 126 transformerPC2D = new TransformingPathConsumer2D(this); 127 128 // Renderer: 129 cache = new MarlinCache(this); 130 renderer = new Renderer(this); // needs MarlinCache from rdrCtx.cache 131 ptg = new MarlinTileGenerator(stats, renderer, cache); 132 133 stroker = new Stroker(this); 134 dasher = new Dasher(this); 135 } 136 137 /** 138 * Disposes this renderer context: 139 * clean up before reusing this context 140 */ 141 void dispose() { 142 if (DO_STATS) { 143 if (stats.totalOffHeap > stats.totalOffHeapMax) { 144 stats.totalOffHeapMax = stats.totalOffHeap; 145 } 146 stats.totalOffHeap = 0L; 147 } 148 stroking = 0; 149 doClip = false; 150 closedPath = false; 151 152 // if context is maked as DIRTY: 153 if (dirty) { 154 // may happen if an exception if thrown in the pipeline processing: 155 // force cleanup of all possible pipelined blocks (except Renderer): 156 157 // NormalizingPathIterator instances: 158 this.nPCPathIterator.dispose(); 159 this.nPQPathIterator.dispose(); 160 // Dasher: 161 this.dasher.dispose(); 162 // Stroker: 163 this.stroker.dispose(); 164 165 // mark context as CLEAN: 166 dirty = false; 167 } 168 } 169 170 Path2D.Float getPath2D() { 171 // resolve reference: 172 Path2D.Float p2d 173 = (refPath2D != null) ? refPath2D.get() : null; 174 175 // create a new Path2D ? 176 if (p2d == null) { 177 p2d = new Path2D.Float(Path2D.WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K 178 179 // update weak reference: 180 refPath2D = new WeakReference<Path2D.Float>(p2d); 181 } 182 // reset the path anyway: 183 p2d.reset(); 184 return p2d; 185 } 186 187 @Override 188 public RendererStats stats() { 189 return stats; 190 } 191 192 @Override 193 public OffHeapArray newOffHeapArray(final long initialSize) { 194 if (DO_STATS) { 195 stats.totalOffHeapInitial += initialSize; 196 } 197 return new OffHeapArray(cleanerObj, initialSize); 198 } 199 200 @Override 201 public IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) { 202 return cleanIntCache.createRef(initialSize); 203 } 204 205 IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) { 206 return dirtyIntCache.createRef(initialSize); 207 } 208 209 FloatArrayCache.Reference newDirtyFloatArrayRef(final int initialSize) { 210 return dirtyFloatCache.createRef(initialSize); 211 } 212 213 ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) { 214 return dirtyByteCache.createRef(initialSize); 215 } 216 }