1 /* 2 * Copyright (c) 2015, 2018, 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 com.sun.marlin; 27 28 import java.lang.ref.WeakReference; 29 import java.util.concurrent.atomic.AtomicInteger; 30 import com.sun.javafx.geom.Path2D; 31 import com.sun.javafx.geom.Rectangle; 32 import com.sun.marlin.ArrayCacheConst.CacheStats; 33 import com.sun.marlin.TransformingPathConsumer2D.CurveBasicMonotonizer; 34 import com.sun.marlin.TransformingPathConsumer2D.CurveClipSplitter; 35 import com.sun.util.reentrant.ReentrantContext; 36 37 /** 38 * This class is a renderer context dedicated to a single thread 39 */ 40 public final class RendererContext extends ReentrantContext implements MarlinConst { 41 42 // RendererContext creation counter 43 private static final AtomicInteger CTX_COUNT = new AtomicInteger(1); 44 45 /** 46 * Create a new renderer context 47 * 48 * @return new RendererContext instance 49 */ 50 public static RendererContext createContext() { 51 return new RendererContext("ctx" 52 + Integer.toString(CTX_COUNT.getAndIncrement())); 53 } 54 55 // Smallest object used as Cleaner's parent reference 56 private final Object cleanerObj; 57 // dirty flag indicating an exception occured during pipeline in pathTo() 58 public boolean dirty = false; 59 // shared data 60 public final float[] float6 = new float[6]; 61 // shared curve (dirty) (Renderer / Stroker) 62 final Curve curve = new Curve(); 63 // MarlinRenderingEngine.TransformingPathConsumer2D 64 public final TransformingPathConsumer2D transformerPC2D; 65 // recycled Path2D instance (weak) 66 private WeakReference<Path2D> refPath2D = null; 67 public final Renderer renderer; 68 public final Stroker stroker; 69 // Simplifies out collinear lines 70 public final CollinearSimplifier simplifier = new CollinearSimplifier(); 71 // Simplifies path 72 public final PathSimplifier pathSimplifier = new PathSimplifier(); 73 public final Dasher dasher; 74 // flag indicating the shape is stroked (1) or filled (0) 75 int stroking = 0; 76 // flag indicating to clip the shape 77 public boolean doClip = false; 78 // flag indicating if the path is closed or not (in advance) to handle properly caps 79 boolean closedPath = false; 80 // clip rectangle (ymin, ymax, xmin, xmax): 81 public final float[] clipRect = new float[4]; 82 // clip inverse scale (mean) to adjust length checks 83 public float clipInvScale = 0.0f; 84 // CurveBasicMonotonizer instance 85 public final CurveBasicMonotonizer monotonizer; 86 // CurveClipSplitter instance 87 final CurveClipSplitter curveClipSplitter; 88 89 // MarlinFX specific: 90 // shared memory between renderer instances: 91 final RendererSharedMemory rdrMem; 92 private RendererNoAA rendererNoAA = null; 93 // dirty bbox rectangle 94 public final Rectangle clip = new Rectangle(); 95 // dirty MaskMarlinAlphaConsumer 96 public MaskMarlinAlphaConsumer consumer = null; 97 98 // Array caches: 99 /* clean int[] cache (zero-filled) = 5 refs */ 100 private final IntArrayCache cleanIntCache = new IntArrayCache(true, 5); 101 /* dirty int[] cache = 5 refs */ 102 private final IntArrayCache dirtyIntCache = new IntArrayCache(false, 5); 103 /* dirty float[] cache = 4 refs (2 polystack) */ 104 private final FloatArrayCache dirtyFloatCache = new FloatArrayCache(false, 4); 105 /* dirty byte[] cache = 2 ref (2 polystack) */ 106 private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 2); 107 108 // RendererContext statistics 109 final RendererStats stats; 110 111 /** 112 * Constructor 113 * 114 * @param name context name (debugging) 115 */ 116 RendererContext(final String name) { 117 if (LOG_CREATE_CONTEXT) { 118 MarlinUtils.logInfo("new RendererContext = " + name); 119 } 120 this.cleanerObj = new Object(); 121 122 // create first stats (needed by newOffHeapArray): 123 if (DO_STATS || DO_MONITORS) { 124 stats = RendererStats.createInstance(cleanerObj, name); 125 // push cache stats: 126 stats.cacheStats = new CacheStats[] { cleanIntCache.stats, 127 dirtyIntCache.stats, dirtyFloatCache.stats, dirtyByteCache.stats 128 }; 129 } else { 130 stats = null; 131 } 132 133 // curve monotonizer & clip subdivider (before transformerPC2D init) 134 monotonizer = new CurveBasicMonotonizer(this); 135 curveClipSplitter = new CurveClipSplitter(this); 136 137 // MarlinRenderingEngine.TransformingPathConsumer2D 138 transformerPC2D = new TransformingPathConsumer2D(this); 139 140 // Renderer shared memory: 141 rdrMem = new RendererSharedMemory(this); 142 143 // Renderer: 144 renderer = new Renderer(this); 145 146 stroker = new Stroker(this); 147 dasher = new Dasher(this); 148 } 149 150 /** 151 * Disposes this renderer context: 152 * clean up before reusing this context 153 */ 154 public void dispose() { 155 if (DO_STATS) { 156 if (stats.totalOffHeap > stats.totalOffHeapMax) { 157 stats.totalOffHeapMax = stats.totalOffHeap; 158 } 159 stats.totalOffHeap = 0L; 160 } 161 stroking = 0; 162 doClip = false; 163 closedPath = false; 164 clipInvScale = 0.0f; 165 166 // if context is maked as DIRTY: 167 if (dirty) { 168 // may happen if an exception if thrown in the pipeline processing: 169 // force cleanup of all possible pipelined blocks (except Renderer): 170 171 // Dasher: 172 this.dasher.dispose(); 173 // Stroker: 174 this.stroker.dispose(); 175 176 // mark context as CLEAN: 177 dirty = false; 178 } 179 } 180 181 public Path2D getPath2D() { 182 // resolve reference: 183 Path2D p2d = (refPath2D != null) ? refPath2D.get() : null; 184 185 // create a new Path2D ? 186 if (p2d == null) { 187 p2d = new Path2D(WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K 188 189 // update weak reference: 190 refPath2D = new WeakReference<Path2D>(p2d); 191 } 192 // reset the path anyway: 193 p2d.reset(); 194 return p2d; 195 } 196 197 public RendererNoAA getRendererNoAA() { 198 if (rendererNoAA == null) { 199 rendererNoAA = new RendererNoAA(this); 200 } 201 return rendererNoAA; 202 } 203 204 OffHeapArray newOffHeapArray(final long initialSize) { 205 if (DO_STATS) { 206 stats.totalOffHeapInitial += initialSize; 207 } 208 return new OffHeapArray(cleanerObj, initialSize); 209 } 210 211 IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) { 212 return cleanIntCache.createRef(initialSize); 213 } 214 215 IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) { 216 return dirtyIntCache.createRef(initialSize); 217 } 218 219 FloatArrayCache.Reference newDirtyFloatArrayRef(final int initialSize) { 220 return dirtyFloatCache.createRef(initialSize); 221 } 222 223 ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) { 224 return dirtyByteCache.createRef(initialSize); 225 } 226 227 static final class RendererSharedMemory { 228 229 // edges [ints] stored in off-heap memory 230 final OffHeapArray edges; 231 232 // edgeBuckets ref (clean) 233 final IntArrayCache.Reference edgeBuckets_ref; 234 // edgeBucketCounts ref (clean) 235 final IntArrayCache.Reference edgeBucketCounts_ref; 236 237 // alphaLine ref (clean) 238 final IntArrayCache.Reference alphaLine_ref; 239 240 // crossings ref (dirty) 241 final IntArrayCache.Reference crossings_ref; 242 // edgePtrs ref (dirty) 243 final IntArrayCache.Reference edgePtrs_ref; 244 // merge sort initial arrays 245 // aux_crossings ref (dirty) 246 final IntArrayCache.Reference aux_crossings_ref; 247 // aux_edgePtrs ref (dirty) 248 final IntArrayCache.Reference aux_edgePtrs_ref; 249 250 // blkFlags ref (clean) 251 final IntArrayCache.Reference blkFlags_ref; 252 253 RendererSharedMemory(final RendererContext rdrCtx) { 254 edges = rdrCtx.newOffHeapArray(INITIAL_EDGES_CAPACITY); // 96K 255 256 edgeBuckets_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K 257 edgeBucketCounts_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K 258 259 // 4096 pixels large 260 alphaLine_ref = rdrCtx.newCleanIntArrayRef(INITIAL_AA_ARRAY); // 16K 261 262 crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K 263 aux_crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K 264 edgePtrs_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K 265 aux_edgePtrs_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K 266 267 blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line 268 } 269 } 270 }