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.geom.Path2D;
29 import java.lang.ref.WeakReference;
30 import java.util.concurrent.atomic.AtomicInteger;
31 import sun.java2d.ReentrantContext;
32 import sun.java2d.marlin.ArrayCacheConst.CacheStats;
33 import sun.java2d.marlin.DMarlinRenderingEngine.NormalizingPathIterator;
34
35 /**
36 * This class is a renderer context dedicated to a single thread
37 */
38 final class DRendererContext extends ReentrantContext implements IRendererContext {
39
40 // RendererContext creation counter
41 private static final AtomicInteger CTX_COUNT = new AtomicInteger(1);
42
43 /**
44 * Create a new renderer context
45 *
46 * @return new RendererContext instance
47 */
48 static DRendererContext createContext() {
49 return new DRendererContext("ctx"
50 + Integer.toString(CTX_COUNT.getAndIncrement()));
51 }
52
53 // Smallest object used as Cleaner's parent reference
54 private final Object cleanerObj;
55 // dirty flag indicating an exception occured during pipeline in pathTo()
56 boolean dirty = false;
57 // shared data
58 final double[] double6 = new double[6];
59 // shared curve (dirty) (Renderer / Stroker)
60 final DCurve curve = new DCurve();
61 // MarlinRenderingEngine NormalizingPathIterator NearestPixelCenter:
62 final NormalizingPathIterator nPCPathIterator;
63 // MarlinRenderingEngine NearestPixelQuarter NormalizingPathIterator:
64 final NormalizingPathIterator nPQPathIterator;
65 // MarlinRenderingEngine.TransformingPathConsumer2D
66 final DTransformingPathConsumer2D transformerPC2D;
67 // recycled Path2D instance (weak)
68 private WeakReference<Path2D.Double> refPath2D = null;
69 final DRenderer renderer;
70 final DStroker stroker;
71 // Simplifies out collinear lines
72 final DCollinearSimplifier simplifier = new DCollinearSimplifier();
73 final DDasher dasher;
74 final MarlinTileGenerator ptg;
75 final MarlinCache cache;
76 // flag indicating the shape is stroked (1) or filled (0)
77 int stroking = 0;
78
79 // Array caches:
80 /* clean int[] cache (zero-filled) = 5 refs */
81 private final IntArrayCache cleanIntCache = new IntArrayCache(true, 5);
82 /* dirty int[] cache = 4 refs */
83 private final IntArrayCache dirtyIntCache = new IntArrayCache(false, 4);
84 /* dirty double[] cache = 3 refs */
85 private final DoubleArrayCache dirtyDoubleCache = new DoubleArrayCache(false, 3);
86 /* dirty byte[] cache = 1 ref */
87 private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 1);
88
89 // RendererContext statistics
90 final RendererStats stats;
91
92 final PathConsumer2DAdapter p2dAdapter = new PathConsumer2DAdapter();
93
94
95 /**
96 * Constructor
97 *
98 * @param name context name (debugging)
99 */
100 DRendererContext(final String name) {
101 if (LOG_CREATE_CONTEXT) {
102 MarlinUtils.logInfo("new RendererContext = " + name);
103 }
104 this.cleanerObj = new Object();
105
106 // create first stats (needed by newOffHeapArray):
107 if (DO_STATS || DO_MONITORS) {
108 stats = RendererStats.createInstance(cleanerObj, name);
109 // push cache stats:
110 stats.cacheStats = new CacheStats[] { cleanIntCache.stats,
111 dirtyIntCache.stats, dirtyDoubleCache.stats, dirtyByteCache.stats
112 };
113 } else {
114 stats = null;
115 }
116
117 // NormalizingPathIterator instances:
118 nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(double6);
119 nPQPathIterator = new NormalizingPathIterator.NearestPixelQuarter(double6);
120
121 // MarlinRenderingEngine.TransformingPathConsumer2D
122 transformerPC2D = new DTransformingPathConsumer2D();
123
124 // Renderer:
125 cache = new MarlinCache(this);
126 renderer = new DRenderer(this); // needs MarlinCache from rdrCtx.cache
127 ptg = new MarlinTileGenerator(stats, renderer, cache);
128
129 stroker = new DStroker(this);
130 dasher = new DDasher(this);
131 }
132
133 /**
134 * Disposes this renderer context:
135 * clean up before reusing this context
136 */
137 void dispose() {
138 if (DO_STATS) {
139 if (stats.totalOffHeap > stats.totalOffHeapMax) {
140 stats.totalOffHeapMax = stats.totalOffHeap;
141 }
142 stats.totalOffHeap = 0L;
143 }
144 stroking = 0;
145 // if context is maked as DIRTY:
146 if (dirty) {
147 // may happen if an exception if thrown in the pipeline processing:
148 // force cleanup of all possible pipelined blocks (except Renderer):
149
150 // NormalizingPathIterator instances:
151 this.nPCPathIterator.dispose();
152 this.nPQPathIterator.dispose();
153 // Dasher:
154 this.dasher.dispose();
155 // Stroker:
156 this.stroker.dispose();
157
158 // mark context as CLEAN:
159 dirty = false;
160 }
161 }
162
163 Path2D.Double getPath2D() {
164 // resolve reference:
165 Path2D.Double p2d
166 = (refPath2D != null) ? refPath2D.get() : null;
167
168 // create a new Path2D ?
169 if (p2d == null) {
170 p2d = new Path2D.Double(Path2D.WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K
171
172 // update weak reference:
173 refPath2D = new WeakReference<Path2D.Double>(p2d);
174 }
175 // reset the path anyway:
176 p2d.reset();
177 return p2d;
178 }
179
180 @Override
181 public RendererStats stats() {
182 return stats;
183 }
184
185 @Override
186 public OffHeapArray newOffHeapArray(final long initialSize) {
187 if (DO_STATS) {
188 stats.totalOffHeapInitial += initialSize;
189 }
190 return new OffHeapArray(cleanerObj, initialSize);
191 }
192
193 @Override
194 public IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) {
195 return cleanIntCache.createRef(initialSize);
196 }
197
198 IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) {
199 return dirtyIntCache.createRef(initialSize);
200 }
201
202 DoubleArrayCache.Reference newDirtyDoubleArrayRef(final int initialSize) {
203 return dirtyDoubleCache.createRef(initialSize);
204 }
205
206 ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) {
207 return dirtyByteCache.createRef(initialSize);
208 }
209
210 static final class PathConsumer2DAdapter implements DPathConsumer2D {
211 private sun.awt.geom.PathConsumer2D out;
212
213 PathConsumer2DAdapter() {}
214
215 PathConsumer2DAdapter init(sun.awt.geom.PathConsumer2D out) {
216 this.out = out;
217 return this;
218 }
219
220 @Override
221 public void moveTo(double x0, double y0) {
222 out.moveTo((float)x0, (float)y0);
223 }
224
225 @Override
226 public void lineTo(double x1, double y1) {
227 out.lineTo((float)x1, (float)y1);
228 }
229
230 @Override
231 public void closePath() {
232 out.closePath();
233 }
234
235 @Override
236 public void pathDone() {
237 out.pathDone();
238 }
239
240 @Override
241 public void curveTo(double x1, double y1,
242 double x2, double y2,
243 double x3, double y3)
244 {
245 out.curveTo((float)x1, (float)y1,
246 (float)x2, (float)y2,
247 (float)x3, (float)y3);
248 }
249
250 @Override
251 public void quadTo(double x1, double y1, double x2, double y2) {
252 out.quadTo((float)x1, (float)y1, (float)x2, (float)y2);
253 }
254
255 @Override
256 public long getNativeConsumer() {
257 throw new InternalError("Not using a native peer");
258 }
259 }
260 }