Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/java2d/SurfaceDataProxy.java
38829 views
/*1* Copyright (c) 2007, 2013, 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;2627import java.awt.Color;28import java.awt.Rectangle;29import java.awt.AlphaComposite;30import java.awt.GraphicsEnvironment;3132import sun.awt.DisplayChangedListener;33import sun.java2d.StateTrackable.State;34import sun.java2d.loops.CompositeType;35import sun.java2d.loops.SurfaceType;36import sun.java2d.loops.Blit;37import sun.java2d.loops.BlitBg;38import sun.awt.image.SurfaceManager;39import sun.awt.image.SurfaceManager.FlushableCacheData;4041import java.security.AccessController;42import sun.security.action.GetPropertyAction;4344/**45* The proxy class encapsulates the logic for managing alternate46* SurfaceData representations of a primary SurfaceData.47* The main class will handle tracking the state changes of the48* primary SurfaceData and updating the associated SurfaceData49* proxy variants.50* <p>51* Subclasses have 2 main responsibilities:52* <ul>53* <li> Override the isSupportedOperation() method to determine if54* a given operation can be accelerated with a given source55* SurfaceData56* <li> Override the validateSurfaceData() method to create or update57* a given accelerated surface to hold the pixels for the indicated58* source SurfaceData59* </ul>60* If necessary, a subclass may also override the updateSurfaceData61* method to transfer the pixels to the accelerated surface.62* By default the parent class will transfer the pixels using a63* standard Blit operation between the two SurfaceData objects.64*/65public abstract class SurfaceDataProxy66implements DisplayChangedListener, SurfaceManager.FlushableCacheData67{68private static boolean cachingAllowed;69private static int defaultThreshold;7071static {72cachingAllowed = true;73String manimg = AccessController.doPrivileged(74new GetPropertyAction("sun.java2d.managedimages"));75if (manimg != null && manimg.equals("false")) {76cachingAllowed = false;77System.out.println("Disabling managed images");78}7980defaultThreshold = 1;81String num = AccessController.doPrivileged(82new GetPropertyAction("sun.java2d.accthreshold"));83if (num != null) {84try {85int parsed = Integer.parseInt(num);86if (parsed >= 0) {87defaultThreshold = parsed;88System.out.println("New Default Acceleration Threshold: " +89defaultThreshold);90}91} catch (NumberFormatException e) {92System.err.println("Error setting new threshold:" + e);93}94}95}9697public static boolean isCachingAllowed() {98return cachingAllowed;99}100101/**102* Determine if an alternate form for the srcData is needed103* and appropriate from the given operational parameters.104*/105public abstract boolean isSupportedOperation(SurfaceData srcData,106int txtype,107CompositeType comp,108Color bgColor);109110/**111* Construct an alternate form of the given SurfaceData.112* The contents of the returned SurfaceData may be undefined113* since the calling code will take care of updating the114* contents with a subsequent call to updateSurfaceData.115* <p>116* If the method returns null then there was a problem with117* allocating the accelerated surface. The getRetryTracker()118* method will be called to track when to attempt another119* revalidation.120*/121public abstract SurfaceData validateSurfaceData(SurfaceData srcData,122SurfaceData cachedData,123int w, int h);124125/**126* If the subclass is unable to validate or create a cached127* SurfaceData then this method will be used to get a128* StateTracker object that will indicate when to attempt129* to validate the surface again. Subclasses may return130* trackers which count down an ever increasing threshold131* to provide hysteresis on creating surfaces during low132* memory conditions. The default implementation just waits133* another "threshold" number of accesses before trying again.134*/135public StateTracker getRetryTracker(SurfaceData srcData) {136return new CountdownTracker(threshold);137}138139public static class CountdownTracker implements StateTracker {140private int countdown;141142public CountdownTracker(int threshold) {143this.countdown = threshold;144}145146public synchronized boolean isCurrent() {147return (--countdown >= 0);148}149}150151/**152* This instance is for cases where a caching implementation153* determines that a particular source image will never need154* to be cached - either the source SurfaceData was of an155* incompatible type, or it was in an UNTRACKABLE state or156* some other factor is discovered that permanently prevents157* acceleration or caching.158* This class optimally implements NOP variants of all necessary159* methods to avoid caching with a minimum of fuss.160*/161public static SurfaceDataProxy UNCACHED = new SurfaceDataProxy(0) {162@Override163public boolean isAccelerated() {164return false;165}166167@Override168public boolean isSupportedOperation(SurfaceData srcData,169int txtype,170CompositeType comp,171Color bgColor)172{173return false;174}175176@Override177public SurfaceData validateSurfaceData(SurfaceData srcData,178SurfaceData cachedData,179int w, int h)180{181throw new InternalError("UNCACHED should never validate SDs");182}183184@Override185public SurfaceData replaceData(SurfaceData srcData,186int txtype,187CompositeType comp,188Color bgColor)189{190// Not necessary to override this, but doing so is faster191return srcData;192}193};194195// The number of attempts to copy from a STABLE source before196// a cached copy is created or updated.197private int threshold;198199/*200* Source tracking data201*202* Every time that srcTracker is out of date we will reset numtries203* to threshold and set the cacheTracker to one that is non-current.204* numtries will then count down to 0 at which point the cacheTracker205* will remind us that we need to update the cachedSD before we can206* use it.207*208* Note that since these fields interrelate we should synchronize209* whenever we update them, but it should be OK to read them210* without synchronization.211*/212private StateTracker srcTracker;213private int numtries;214215/*216* Cached data217*218* We cache a SurfaceData created by the subclass in cachedSD and219* track its state (isValid and !surfaceLost) in cacheTracker.220*221* Also, when we want to note that cachedSD needs to be updated222* we replace the cacheTracker with a NEVER_CURRENT tracker which223* will cause us to try to revalidate and update the surface on224* next use.225*/226private SurfaceData cachedSD;227private StateTracker cacheTracker;228229/*230* Are we still the best object to control caching of data231* for the source image?232*/233private boolean valid;234235/**236* Create a SurfaceData proxy manager that attempts to create237* and cache a variant copy of the source SurfaceData after238* the default threshold number of attempts to copy from the239* STABLE source.240*/241public SurfaceDataProxy() {242this(defaultThreshold);243}244245/**246* Create a SurfaceData proxy manager that attempts to create247* and cache a variant copy of the source SurfaceData after248* the specified threshold number of attempts to copy from249* the STABLE source.250*/251public SurfaceDataProxy(int threshold) {252this.threshold = threshold;253254this.srcTracker = StateTracker.NEVER_CURRENT;255// numtries will be reset on first use256this.cacheTracker = StateTracker.NEVER_CURRENT;257258this.valid = true;259}260261/**262* Returns true iff this SurfaceData proxy is still the best263* way to control caching of the given source on the given264* destination.265*/266public boolean isValid() {267return valid;268}269270/**271* Sets the valid state to false so that the next time this272* proxy is fetched to generate a replacement SurfaceData,273* the code in SurfaceData knows to replace the proxy first.274*/275public void invalidate() {276this.valid = false;277}278279/**280* Flush all cached resources as per the FlushableCacheData interface.281* The deaccelerated parameter indicates if the flush is282* happening because the associated surface is no longer283* being accelerated (for instance the acceleration priority284* is set below the threshold needed for acceleration).285* Returns a boolean that indicates if the cached object is286* no longer needed and should be removed from the cache.287*/288public boolean flush(boolean deaccelerated) {289if (deaccelerated) {290invalidate();291}292flush();293return !isValid();294}295296/**297* Actively flushes (drops and invalidates) the cached surface298* so that it can be reclaimed quickly.299*/300public synchronized void flush() {301SurfaceData csd = this.cachedSD;302this.cachedSD = null;303this.cacheTracker = StateTracker.NEVER_CURRENT;304if (csd != null) {305csd.flush();306}307}308309/**310* Returns true iff this SurfaceData proxy is still valid311* and if it has a currently cached replacement that is also312* valid and current.313*/314public boolean isAccelerated() {315return (isValid() &&316srcTracker.isCurrent() &&317cacheTracker.isCurrent());318}319320/**321* This method should be called from subclasses which create322* cached SurfaceData objects that depend on the current323* properties of the display.324*/325protected void activateDisplayListener() {326GraphicsEnvironment ge =327GraphicsEnvironment.getLocalGraphicsEnvironment();328// We could have a HeadlessGE at this point, so double-check before329// assuming anything.330// Also, no point in listening to display change events if331// the image is never going to be accelerated.332if (ge instanceof SunGraphicsEnvironment) {333((SunGraphicsEnvironment)ge).addDisplayChangedListener(this);334}335}336337/**338* Invoked when the display mode has changed.339* This method will invalidate and drop the internal cachedSD object.340*/341public void displayChanged() {342flush();343}344345/**346* Invoked when the palette has changed.347*/348public void paletteChanged() {349// We could potentially get away with just resetting cacheTracker350// here but there is a small window of vulnerability in the351// replaceData method where we could be just finished with352// updating the cachedSD when this method is called and even353// though we set a non-current cacheTracker here it will then354// immediately get set to a current one by the thread that is355// updating the cachedSD. It is safer to just replace the356// srcTracker with a non-current version that will trigger a357// full update cycle the next time this proxy is used.358// The downside is having to go through a full threshold count359// before we can update and use our cache again, but palette360// changes should be relatively rare...361this.srcTracker = StateTracker.NEVER_CURRENT;362}363364/**365* This method attempts to replace the srcData with a cached version.366* It relies on the subclass to determine if the cached version will367* be useful given the operational parameters.368* This method checks any preexisting cached copy for being "up to date"369* and tries to update it if it is stale or non-existant and the370* appropriate number of accesses have occurred since it last was stale.371* <p>372* An outline of the process is as follows:373* <ol>374* <li> Check the operational parameters (txtype, comp, bgColor)375* to make sure that the operation is supported. Return the376* original SurfaceData if the operation cannot be accelerated.377* <li> Check the tracker for the source surface to see if it has378* remained stable since it was last cached. Update the state379* variables to cause both a threshold countdown and an update380* of the cached copy if it is not. (Setting cacheTracker to381* NEVER_CURRENT effectively marks it as "needing to be updated".)382* <li> Check the tracker for the cached copy to see if is still383* valid and up to date. Note that the cacheTracker may be384* non-current if either something happened to the cached copy385* (eg. surfaceLost) or if the source was out of date and the386* cacheTracker was set to NEVER_CURRENT to force an update.387* Decrement the countdown and copy the source to the cache388* as necessary and then update the variables to show that389* the cached copy is stable.390* </ol>391*/392public SurfaceData replaceData(SurfaceData srcData,393int txtype,394CompositeType comp,395Color bgColor)396{397if (isSupportedOperation(srcData, txtype, comp, bgColor)) {398// First deal with tracking the source.399if (!srcTracker.isCurrent()) {400synchronized (this) {401this.numtries = threshold;402this.srcTracker = srcData.getStateTracker();403this.cacheTracker = StateTracker.NEVER_CURRENT;404}405406if (!srcTracker.isCurrent()) {407// Dynamic or Untrackable (or a very recent modification)408if (srcData.getState() == State.UNTRACKABLE) {409// UNTRACKABLE means we can never cache again.410411// Invalidate so we get replaced next time we are used412// (presumably with an UNCACHED proxy).413invalidate();414415// Aggressively drop our reference to the cachedSD416// in case this proxy is not consulted again (and417// thus replaced) for a long time.418flush();419}420return srcData;421}422}423424// Then deal with checking the validity of the cached SurfaceData425SurfaceData csd = this.cachedSD;426if (!cacheTracker.isCurrent()) {427// Next make sure the dust has settled428synchronized (this) {429if (numtries > 0) {430--numtries;431return srcData;432}433}434435Rectangle r = srcData.getBounds();436int w = r.width;437int h = r.height;438439// Snapshot the tracker in case it changes while440// we are updating the cached SD...441StateTracker curTracker = srcTracker;442443csd = validateSurfaceData(srcData, csd, w, h);444if (csd == null) {445synchronized (this) {446if (curTracker == srcTracker) {447this.cacheTracker = getRetryTracker(srcData);448this.cachedSD = null;449}450}451return srcData;452}453454updateSurfaceData(srcData, csd, w, h);455if (!csd.isValid()) {456return srcData;457}458459synchronized (this) {460// We only reset these variables if the tracker from461// before the surface update is still in use and current462// Note that we must use a srcTracker that was fetched463// from before the update process to make sure that we464// do not lose some pixel changes in the shuffle.465if (curTracker == srcTracker && curTracker.isCurrent()) {466this.cacheTracker = csd.getStateTracker();467this.cachedSD = csd;468}469}470}471472if (csd != null) {473return csd;474}475}476477return srcData;478}479480/**481* This is the default implementation for updating the cached482* SurfaceData from the source (primary) SurfaceData.483* A simple Blit is used to copy the pixels from the source to484* the destination SurfaceData.485* A subclass can override this implementation if a more complex486* operation is required to update its cached copies.487*/488public void updateSurfaceData(SurfaceData srcData,489SurfaceData dstData,490int w, int h)491{492SurfaceType srcType = srcData.getSurfaceType();493SurfaceType dstType = dstData.getSurfaceType();494Blit blit = Blit.getFromCache(srcType,495CompositeType.SrcNoEa,496dstType);497blit.Blit(srcData, dstData,498AlphaComposite.Src, null,4990, 0, 0, 0, w, h);500dstData.markDirty();501}502503/**504* This is an alternate implementation for updating the cached505* SurfaceData from the source (primary) SurfaceData using a506* background color for transparent pixels.507* A simple BlitBg is used to copy the pixels from the source to508* the destination SurfaceData with the specified bgColor.509* A subclass can override the normal updateSurfaceData method510* and call this implementation instead if it wants to use color511* keying for bitmask images.512*/513public void updateSurfaceDataBg(SurfaceData srcData,514SurfaceData dstData,515int w, int h, Color bgColor)516{517SurfaceType srcType = srcData.getSurfaceType();518SurfaceType dstType = dstData.getSurfaceType();519BlitBg blitbg = BlitBg.getFromCache(srcType,520CompositeType.SrcNoEa,521dstType);522blitbg.BlitBg(srcData, dstData,523AlphaComposite.Src, null, bgColor.getRGB(),5240, 0, 0, 0, w, h);525dstData.markDirty();526}527}528529530