Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/java2d/marlin/RendererContext.java
38918 views
/*1* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.marlin;2627import java.awt.geom.Path2D;28import java.lang.ref.WeakReference;29import java.util.concurrent.atomic.AtomicInteger;30import sun.java2d.ReentrantContext;31import sun.java2d.ReentrantContextProvider;32import static sun.java2d.marlin.ArrayCache.*;33import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator;34import static sun.java2d.marlin.MarlinUtils.logInfo;3536/**37* This class is a renderer context dedicated to a single thread38*/39final class RendererContext extends ReentrantContext implements MarlinConst {4041// RendererContext creation counter42private static final AtomicInteger contextCount = new AtomicInteger(1);43// RendererContext statistics44static final RendererStats stats = (doStats || doMonitors)45? RendererStats.getInstance(): null;4647private static final boolean USE_CACHE_HARD_REF = doStats48|| (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK);4950/**51* Create a new renderer context52*53* @return new RendererContext instance54*/55static RendererContext createContext() {56final RendererContext newCtx = new RendererContext("ctx"57+ Integer.toString(contextCount.getAndIncrement()));5859if (RendererContext.stats != null) {60RendererContext.stats.allContexts.add(newCtx);61}62return newCtx;63}6465// context name (debugging purposes)66final String name;67// dirty flag indicating an exception occured during pipeline in pathTo()68boolean dirty = false;69// dynamic array caches kept using weak reference (low memory footprint)70WeakReference<ArrayCachesHolder> refArrayCaches = null;71// hard reference to array caches (for statistics)72ArrayCachesHolder hardRefArrayCaches = null;73// shared data74final float[] float6 = new float[6];75// shared curve (dirty) (Renderer / Stroker)76final Curve curve = new Curve();77// MarlinRenderingEngine NormalizingPathIterator NearestPixelCenter:78final NormalizingPathIterator nPCPathIterator;79// MarlinRenderingEngine NearestPixelQuarter NormalizingPathIterator:80final NormalizingPathIterator nPQPathIterator;81// MarlinRenderingEngine.TransformingPathConsumer2D82final TransformingPathConsumer2D transformerPC2D;83// recycled Path2D instance84Path2D.Float p2d = null;85final Renderer renderer;86final Stroker stroker;87// Simplifies out collinear lines88final CollinearSimplifier simplifier = new CollinearSimplifier();89final Dasher dasher;90final MarlinTileGenerator ptg;91final MarlinCache cache;92// flag indicating the shape is stroked (1) or filled (0)93int stroking = 0;9495/**96* Constructor97*98* @param name context name (debugging)99*/100RendererContext(final String name) {101if (logCreateContext) {102MarlinUtils.logInfo("new RendererContext = " + name);103}104105this.name = name;106107// NormalizingPathIterator instances:108nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(float6);109nPQPathIterator = new NormalizingPathIterator.NearestPixelQuarter(float6);110111// MarlinRenderingEngine.TransformingPathConsumer2D112transformerPC2D = new TransformingPathConsumer2D();113114// Renderer:115cache = new MarlinCache(this);116renderer = new Renderer(this); // needs MarlinCache from rdrCtx.cache117ptg = new MarlinTileGenerator(renderer);118119stroker = new Stroker(this);120dasher = new Dasher(this);121}122123/**124* Disposes this renderer context:125* clean up before reusing this context126*/127void dispose() {128stroking = 0;129// reset hard reference to array caches if needed:130if (!USE_CACHE_HARD_REF) {131hardRefArrayCaches = null;132}133// if context is maked as DIRTY:134if (dirty) {135// may happen if an exception if thrown in the pipeline processing:136// force cleanup of all possible pipelined blocks (except Renderer):137138// NormalizingPathIterator instances:139this.nPCPathIterator.dispose();140this.nPQPathIterator.dispose();141// Dasher:142this.dasher.dispose();143// Stroker:144this.stroker.dispose();145146// mark context as CLEAN:147dirty = false;148}149}150151// Array caches152ArrayCachesHolder getArrayCachesHolder() {153// Use hard reference first (cached resolved weak reference):154ArrayCachesHolder holder = hardRefArrayCaches;155if (holder == null) {156// resolve reference:157holder = (refArrayCaches != null)158? refArrayCaches.get()159: null;160// create a new ArrayCachesHolder if none is available161if (holder == null) {162if (logCreateContext) {163MarlinUtils.logInfo("new ArrayCachesHolder for "164+ "RendererContext = " + name);165}166167holder = new ArrayCachesHolder();168169if (USE_CACHE_HARD_REF) {170// update hard reference:171hardRefArrayCaches = holder;172}173174// update weak reference:175refArrayCaches = new WeakReference<ArrayCachesHolder>(holder);176}177}178return holder;179}180181// dirty byte array cache182ByteArrayCache getDirtyByteArrayCache(final int length) {183final int bucket = ArrayCache.getBucketDirtyBytes(length);184return getArrayCachesHolder().dirtyByteArrayCaches[bucket];185}186187byte[] getDirtyByteArray(final int length) {188if (length <= MAX_DIRTY_BYTE_ARRAY_SIZE) {189return getDirtyByteArrayCache(length).getArray();190}191192if (doStats) {193incOversize();194}195196if (doLogOverSize) {197logInfo("getDirtyByteArray[oversize]: length=\t" + length);198}199200return new byte[length];201}202203void putDirtyByteArray(final byte[] array) {204final int length = array.length;205// odd sized array are non-cached arrays (initial arrays)206// ensure to never store initial arrays in cache:207if (((length & 0x1) == 0) && (length <= MAX_DIRTY_BYTE_ARRAY_SIZE)) {208getDirtyByteArrayCache(length).putDirtyArray(array, length);209}210}211212byte[] widenDirtyByteArray(final byte[] in,213final int usedSize, final int needSize)214{215final int length = in.length;216if (doChecks && length >= needSize) {217return in;218}219if (doStats) {220incResizeDirtyByte();221}222223// maybe change bucket:224// ensure getNewSize() > newSize:225final byte[] res = getDirtyByteArray(getNewSize(usedSize, needSize));226227System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements228229// maybe return current array:230// NO clean-up of array data = DIRTY ARRAY231putDirtyByteArray(in);232233if (doLogWidenArray) {234logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t"235+ usedSize + "\tlength=\t" + length + "\tneeded length=\t"236+ needSize);237}238return res;239}240241// int array cache242IntArrayCache getIntArrayCache(final int length) {243final int bucket = ArrayCache.getBucket(length);244return getArrayCachesHolder().intArrayCaches[bucket];245}246247int[] getIntArray(final int length) {248if (length <= MAX_ARRAY_SIZE) {249return getIntArrayCache(length).getArray();250}251252if (doStats) {253incOversize();254}255256if (doLogOverSize) {257logInfo("getIntArray[oversize]: length=\t" + length);258}259260return new int[length];261}262263// unused264int[] widenIntArray(final int[] in, final int usedSize,265final int needSize, final int clearTo)266{267final int length = in.length;268if (doChecks && length >= needSize) {269return in;270}271if (doStats) {272incResizeInt();273}274275// maybe change bucket:276// ensure getNewSize() > newSize:277final int[] res = getIntArray(getNewSize(usedSize, needSize));278279System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements280281// maybe return current array:282putIntArray(in, 0, clearTo); // ensure all array is cleared (grow-reduce algo)283284if (doLogWidenArray) {285logInfo("widenIntArray[" + res.length + "]: usedSize=\t"286+ usedSize + "\tlength=\t" + length + "\tneeded length=\t"287+ needSize);288}289return res;290}291292void putIntArray(final int[] array, final int fromIndex,293final int toIndex)294{295final int length = array.length;296// odd sized array are non-cached arrays (initial arrays)297// ensure to never store initial arrays in cache:298if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {299getIntArrayCache(length).putArray(array, length, fromIndex, toIndex);300}301}302303// dirty int array cache304IntArrayCache getDirtyIntArrayCache(final int length) {305final int bucket = ArrayCache.getBucket(length);306return getArrayCachesHolder().dirtyIntArrayCaches[bucket];307}308309int[] getDirtyIntArray(final int length) {310if (length <= MAX_ARRAY_SIZE) {311return getDirtyIntArrayCache(length).getArray();312}313314if (doStats) {315incOversize();316}317318if (doLogOverSize) {319logInfo("getDirtyIntArray[oversize]: length=\t" + length);320}321322return new int[length];323}324325int[] widenDirtyIntArray(final int[] in,326final int usedSize, final int needSize)327{328final int length = in.length;329if (doChecks && length >= needSize) {330return in;331}332if (doStats) {333incResizeDirtyInt();334}335336// maybe change bucket:337// ensure getNewSize() > newSize:338final int[] res = getDirtyIntArray(getNewSize(usedSize, needSize));339340System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements341342// maybe return current array:343// NO clean-up of array data = DIRTY ARRAY344putDirtyIntArray(in);345346if (doLogWidenArray) {347logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t"348+ usedSize + "\tlength=\t" + length + "\tneeded length=\t"349+ needSize);350}351return res;352}353354void putDirtyIntArray(final int[] array) {355final int length = array.length;356// odd sized array are non-cached arrays (initial arrays)357// ensure to never store initial arrays in cache:358if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {359getDirtyIntArrayCache(length).putDirtyArray(array, length);360}361}362363// dirty float array cache364FloatArrayCache getDirtyFloatArrayCache(final int length) {365final int bucket = ArrayCache.getBucket(length);366return getArrayCachesHolder().dirtyFloatArrayCaches[bucket];367}368369float[] getDirtyFloatArray(final int length) {370if (length <= MAX_ARRAY_SIZE) {371return getDirtyFloatArrayCache(length).getArray();372}373374if (doStats) {375incOversize();376}377378if (doLogOverSize) {379logInfo("getDirtyFloatArray[oversize]: length=\t" + length);380}381382return new float[length];383}384385float[] widenDirtyFloatArray(final float[] in,386final int usedSize, final int needSize)387{388final int length = in.length;389if (doChecks && length >= needSize) {390return in;391}392if (doStats) {393incResizeDirtyFloat();394}395396// maybe change bucket:397// ensure getNewSize() > newSize:398final float[] res = getDirtyFloatArray(getNewSize(usedSize, needSize));399400System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements401402// maybe return current array:403// NO clean-up of array data = DIRTY ARRAY404putDirtyFloatArray(in);405406if (doLogWidenArray) {407logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t"408+ usedSize + "\tlength=\t" + length + "\tneeded length=\t"409+ needSize);410}411return res;412}413414void putDirtyFloatArray(final float[] array) {415final int length = array.length;416// odd sized array are non-cached arrays (initial arrays)417// ensure to never store initial arrays in cache:418if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {419getDirtyFloatArrayCache(length).putDirtyArray(array, length);420}421}422423/* class holding all array cache instances */424static final class ArrayCachesHolder {425// zero-filled int array cache:426final IntArrayCache[] intArrayCaches;427// dirty array caches:428final IntArrayCache[] dirtyIntArrayCaches;429final FloatArrayCache[] dirtyFloatArrayCaches;430final ByteArrayCache[] dirtyByteArrayCaches;431432ArrayCachesHolder() {433intArrayCaches = new IntArrayCache[BUCKETS];434dirtyIntArrayCaches = new IntArrayCache[BUCKETS];435dirtyFloatArrayCaches = new FloatArrayCache[BUCKETS];436dirtyByteArrayCaches = new ByteArrayCache[BUCKETS];437438for (int i = 0; i < BUCKETS; i++) {439intArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);440// dirty array caches:441dirtyIntArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);442dirtyFloatArrayCaches[i] = new FloatArrayCache(ARRAY_SIZES[i]);443dirtyByteArrayCaches[i] = new ByteArrayCache(DIRTY_BYTE_ARRAY_SIZES[i]);444}445}446}447}448449450