History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/java2d/SurfaceDataProxy.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/java2d/SurfaceDataProxy.java+528−0
@@ -0,0 +1,528 @@
1/*
2 * Copyright (c) 2007, 2008, 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
26package sun.java2d;
27
28import java.awt.Color;
29import java.awt.Rectangle;
30import java.awt.AlphaComposite;
31import java.awt.GraphicsEnvironment;
32
33import sun.awt.DisplayChangedListener;
34import sun.java2d.StateTrackable.State;
35import sun.java2d.loops.CompositeType;
36import sun.java2d.loops.SurfaceType;
37import sun.java2d.loops.Blit;
38import sun.java2d.loops.BlitBg;
39import sun.awt.image.SurfaceManager;
40import sun.awt.image.SurfaceManager.FlushableCacheData;
41
42import java.security.AccessController;
43import sun.security.action.GetPropertyAction;
44
45/**
46 * The proxy class encapsulates the logic for managing alternate
47 * SurfaceData representations of a primary SurfaceData.
48 * The main class will handle tracking the state changes of the
49 * primary SurfaceData and updating the associated SurfaceData
50 * proxy variants.
51 * <p>
52 * Subclasses have 2 main responsibilities:
53 * <ul>
54 * <li> Override the isSupportedOperation() method to determine if
55 * a given operation can be accelerated with a given source
56 * SurfaceData
57 * <li> Override the validateSurfaceData() method to create or update
58 * a given accelerated surface to hold the pixels for the indicated
59 * source SurfaceData
60 * </ul>
61 * If necessary, a subclass may also override the updateSurfaceData
62 * method to transfer the pixels to the accelerated surface.
63 * By default the parent class will transfer the pixels using a
64 * standard Blit operation between the two SurfaceData objects.
65 */
66public abstract class SurfaceDataProxy
67 implements DisplayChangedListener, SurfaceManager.FlushableCacheData
68{
69 private static boolean cachingAllowed;
70 private static int defaultThreshold;
71
72 static {
73 cachingAllowed = true;
74 String manimg = (String)AccessController.doPrivileged(
75 new GetPropertyAction("sun.java2d.managedimages"));
76 if (manimg != null && manimg.equals("false")) {
77 cachingAllowed = false;
78 System.out.println("Disabling managed images");
79 }
80
81 defaultThreshold = 1;
82 String num = (String)AccessController.doPrivileged(
83 new GetPropertyAction("sun.java2d.accthreshold"));
84 if (num != null) {
85 try {
86 int parsed = Integer.parseInt(num);
87 if (parsed >= 0) {
88 defaultThreshold = parsed;
89 System.out.println("New Default Acceleration Threshold: " +
90 defaultThreshold);
91 }
92 } catch (NumberFormatException e) {
93 System.err.println("Error setting new threshold:" + e);
94 }
95 }
96 }
97
98 public static boolean isCachingAllowed() {
99 return cachingAllowed;
100 }
101
102 /**
103 * Determine if an alternate form for the srcData is needed
104 * and appropriate from the given operational parameters.
105 */
106 public abstract boolean isSupportedOperation(SurfaceData srcData,
107 int txtype,
108 CompositeType comp,
109 Color bgColor);
110
111 /**
112 * Construct an alternate form of the given SurfaceData.
113 * The contents of the returned SurfaceData may be undefined
114 * since the calling code will take care of updating the
115 * contents with a subsequent call to updateSurfaceData.
116 * <p>
117 * If the method returns null then there was a problem with
118 * allocating the accelerated surface. The getRetryTracker()
119 * method will be called to track when to attempt another
120 * revalidation.
121 */
122 public abstract SurfaceData validateSurfaceData(SurfaceData srcData,
123 SurfaceData cachedData,
124 int w, int h);
125
126 /**
127 * If the subclass is unable to validate or create a cached
128 * SurfaceData then this method will be used to get a
129 * StateTracker object that will indicate when to attempt
130 * to validate the surface again. Subclasses may return
131 * trackers which count down an ever increasing threshold
132 * to provide hysteresis on creating surfaces during low
133 * memory conditions. The default implementation just waits
134 * another "threshold" number of accesses before trying again.
135 */
136 public StateTracker getRetryTracker(SurfaceData srcData) {
137 return new CountdownTracker(threshold);
138 }
139
140 public static class CountdownTracker implements StateTracker {
141 private int countdown;
142
143 public CountdownTracker(int threshold) {
144 this.countdown = threshold;
145 }
146
147 public synchronized boolean isCurrent() {
148 return (--countdown >= 0);
149 }
150 }
151
152 /**
153 * This instance is for cases where a caching implementation
154 * determines that a particular source image will never need
155 * to be cached - either the source SurfaceData was of an
156 * incompatible type, or it was in an UNTRACKABLE state or
157 * some other factor is discovered that permanently prevents
158 * acceleration or caching.
159 * This class optimally implements NOP variants of all necessary
160 * methods to avoid caching with a minimum of fuss.
161 */
162 public static SurfaceDataProxy UNCACHED = new SurfaceDataProxy(0) {
163 @Override
164 public boolean isAccelerated() {
165 return false;
166 }
167
168 @Override
169 public boolean isSupportedOperation(SurfaceData srcData,
170 int txtype,
171 CompositeType comp,
172 Color bgColor)
173 {
174 return false;
175 }
176
177 @Override
178 public SurfaceData validateSurfaceData(SurfaceData srcData,
179 SurfaceData cachedData,
180 int w, int h)
181 {
182 throw new InternalError("UNCACHED should never validate SDs");
183 }
184
185 @Override
186 public SurfaceData replaceData(SurfaceData srcData,
187 int txtype,
188 CompositeType comp,
189 Color bgColor)
190 {
191 // Not necessary to override this, but doing so is faster
192 return srcData;
193 }
194 };
195
196 // The number of attempts to copy from a STABLE source before
197 // a cached copy is created or updated.
198 private int threshold;
199
200 /*
201 * Source tracking data
202 *
203 * Every time that srcTracker is out of date we will reset numtries
204 * to threshold and set the cacheTracker to one that is non-current.
205 * numtries will then count down to 0 at which point the cacheTracker
206 * will remind us that we need to update the cachedSD before we can
207 * use it.
208 *
209 * Note that since these fields interrelate we should synchronize
210 * whenever we update them, but it should be OK to read them
211 * without synchronization.
212 */
213 private StateTracker srcTracker;
214 private int numtries;
215
216 /*
217 * Cached data
218 *
219 * We cache a SurfaceData created by the subclass in cachedSD and
220 * track its state (isValid and !surfaceLost) in cacheTracker.
221 *
222 * Also, when we want to note that cachedSD needs to be updated
223 * we replace the cacheTracker with a NEVER_CURRENT tracker which
224 * will cause us to try to revalidate and update the surface on
225 * next use.
226 */
227 private SurfaceData cachedSD;
228 private StateTracker cacheTracker;
229
230 /*
231 * Are we still the best object to control caching of data
232 * for the source image?
233 */
234 private boolean valid;
235
236 /**
237 * Create a SurfaceData proxy manager that attempts to create
238 * and cache a variant copy of the source SurfaceData after
239 * the default threshold number of attempts to copy from the
240 * STABLE source.
241 */
242 public SurfaceDataProxy() {
243 this(defaultThreshold);
244 }
245
246 /**
247 * Create a SurfaceData proxy manager that attempts to create
248 * and cache a variant copy of the source SurfaceData after
249 * the specified threshold number of attempts to copy from
250 * the STABLE source.
251 */
252 public SurfaceDataProxy(int threshold) {
253 this.threshold = threshold;
254
255 this.srcTracker = StateTracker.NEVER_CURRENT;
256 // numtries will be reset on first use
257 this.cacheTracker = StateTracker.NEVER_CURRENT;
258
259 this.valid = true;
260 }
261
262 /**
263 * Returns true iff this SurfaceData proxy is still the best
264 * way to control caching of the given source on the given
265 * destination.
266 */
267 public boolean isValid() {
268 return valid;
269 }
270
271 /**
272 * Sets the valid state to false so that the next time this
273 * proxy is fetched to generate a replacement SurfaceData,
274 * the code in SurfaceData knows to replace the proxy first.
275 */
276 public void invalidate() {
277 this.valid = false;
278 }
279
280 /**
281 * Flush all cached resources as per the FlushableCacheData interface.
282 * The deaccelerated parameter indicates if the flush is
283 * happening because the associated surface is no longer
284 * being accelerated (for instance the acceleration priority
285 * is set below the threshold needed for acceleration).
286 * Returns a boolean that indicates if the cached object is
287 * no longer needed and should be removed from the cache.
288 */
289 public boolean flush(boolean deaccelerated) {
290 if (deaccelerated) {
291 invalidate();
292 }
293 flush();
294 return !isValid();
295 }
296
297 /**
298 * Actively flushes (drops and invalidates) the cached surface
299 * so that it can be reclaimed quickly.
300 */
301 public synchronized void flush() {
302 SurfaceData csd = this.cachedSD;
303 this.cachedSD = null;
304 this.cacheTracker = StateTracker.NEVER_CURRENT;
305 if (csd != null) {
306 csd.flush();
307 }
308 }
309
310 /**
311 * Returns true iff this SurfaceData proxy is still valid
312 * and if it has a currently cached replacement that is also
313 * valid and current.
314 */
315 public boolean isAccelerated() {
316 return (isValid() &&
317 srcTracker.isCurrent() &&
318 cacheTracker.isCurrent());
319 }
320
321 /**
322 * This method should be called from subclasses which create
323 * cached SurfaceData objects that depend on the current
324 * properties of the display.
325 */
326 protected void activateDisplayListener() {
327 GraphicsEnvironment ge =
328 GraphicsEnvironment.getLocalGraphicsEnvironment();
329 // We could have a HeadlessGE at this point, so double-check before
330 // assuming anything.
331 // Also, no point in listening to display change events if
332 // the image is never going to be accelerated.
333 if (ge instanceof SunGraphicsEnvironment) {
334 ((SunGraphicsEnvironment)ge).addDisplayChangedListener(this);
335 }
336 }
337
338 /**
339 * Invoked when the display mode has changed.
340 * This method will invalidate and drop the internal cachedSD object.
341 */
342 public void displayChanged() {
343 flush();
344 }
345
346 /**
347 * Invoked when the palette has changed.
348 */
349 public void paletteChanged() {
350 // We could potentially get away with just resetting cacheTracker
351 // here but there is a small window of vulnerability in the
352 // replaceData method where we could be just finished with
353 // updating the cachedSD when this method is called and even
354 // though we set a non-current cacheTracker here it will then
355 // immediately get set to a current one by the thread that is
356 // updating the cachedSD. It is safer to just replace the
357 // srcTracker with a non-current version that will trigger a
358 // full update cycle the next time this proxy is used.
359 // The downside is having to go through a full threshold count
360 // before we can update and use our cache again, but palette
361 // changes should be relatively rare...
362 this.srcTracker = StateTracker.NEVER_CURRENT;
363 }
364
365 /**
366 * This method attempts to replace the srcData with a cached version.
367 * It relies on the subclass to determine if the cached version will
368 * be useful given the operational parameters.
369 * This method checks any preexisting cached copy for being "up to date"
370 * and tries to update it if it is stale or non-existant and the
371 * appropriate number of accesses have occured since it last was stale.
372 * <p>
373 * An outline of the process is as follows:
374 * <ol>
375 * <li> Check the operational parameters (txtype, comp, bgColor)
376 * to make sure that the operation is supported. Return the
377 * original SurfaceData if the operation cannot be accelerated.
378 * <li> Check the tracker for the source surface to see if it has
379 * remained stable since it was last cached. Update the state
380 * variables to cause both a threshold countdown and an update
381 * of the cached copy if it is not. (Setting cacheTracker to
382 * NEVER_CURRENT effectively marks it as "needing to be updated".)
383 * <li> Check the tracker for the cached copy to see if is still
384 * valid and up to date. Note that the cacheTracker may be
385 * non-current if either something happened to the cached copy
386 * (eg. surfaceLost) or if the source was out of date and the
387 * cacheTracker was set to NEVER_CURRENT to force an update.
388 * Decrement the countdown and copy the source to the cache
389 * as necessary and then update the variables to show that
390 * the cached copy is stable.
391 * </ol>
392 */
393 public SurfaceData replaceData(SurfaceData srcData,
394 int txtype,
395 CompositeType comp,
396 Color bgColor)
397 {
398 if (isSupportedOperation(srcData, txtype, comp, bgColor)) {
399 // First deal with tracking the source.
400 if (!srcTracker.isCurrent()) {
401 synchronized (this) {
402 this.numtries = threshold;
403 this.srcTracker = srcData.getStateTracker();
404 this.cacheTracker = StateTracker.NEVER_CURRENT;
405 }
406
407 if (!srcTracker.isCurrent()) {
408 // Dynamic or Untrackable (or a very recent modification)
409 if (srcData.getState() == State.UNTRACKABLE) {
410 // UNTRACKABLE means we can never cache again.
411
412 // Invalidate so we get replaced next time we are used
413 // (presumably with an UNCACHED proxy).
414 invalidate();
415
416 // Aggressively drop our reference to the cachedSD
417 // in case this proxy is not consulted again (and
418 // thus replaced) for a long time.
419 flush();
420 }
421 return srcData;
422 }
423 }
424
425 // Then deal with checking the validity of the cached SurfaceData
426 SurfaceData csd = this.cachedSD;
427 if (!cacheTracker.isCurrent()) {
428 // Next make sure the dust has settled
429 synchronized (this) {
430 if (numtries > 0) {
431 --numtries;
432 return srcData;
433 }
434 }
435
436 Rectangle r = srcData.getBounds();
437 int w = r.width;
438 int h = r.height;
439
440 // Snapshot the tracker in case it changes while
441 // we are updating the cached SD...
442 StateTracker curTracker = srcTracker;
443
444 csd = validateSurfaceData(srcData, csd, w, h);
445 if (csd == null) {
446 synchronized (this) {
447 if (curTracker == srcTracker) {
448 this.cacheTracker = getRetryTracker(srcData);
449 this.cachedSD = null;
450 }
451 }
452 return srcData;
453 }
454
455 updateSurfaceData(srcData, csd, w, h);
456 if (!csd.isValid()) {
457 return srcData;
458 }
459
460 synchronized (this) {
461 // We only reset these variables if the tracker from
462 // before the surface update is still in use and current
463 // Note that we must use a srcTracker that was fetched
464 // from before the update process to make sure that we
465 // do not lose some pixel changes in the shuffle.
466 if (curTracker == srcTracker && curTracker.isCurrent()) {
467 this.cacheTracker = csd.getStateTracker();
468 this.cachedSD = csd;
469 }
470 }
471 }
472
473 if (csd != null) {
474 return csd;
475 }
476 }
477
478 return srcData;
479 }
480
481 /**
482 * This is the default implementation for updating the cached
483 * SurfaceData from the source (primary) SurfaceData.
484 * A simple Blit is used to copy the pixels from the source to
485 * the destination SurfaceData.
486 * A subclass can override this implementation if a more complex
487 * operation is required to update its cached copies.
488 */
489 public void updateSurfaceData(SurfaceData srcData,
490 SurfaceData dstData,
491 int w, int h)
492 {
493 SurfaceType srcType = srcData.getSurfaceType();
494 SurfaceType dstType = dstData.getSurfaceType();
495 Blit blit = Blit.getFromCache(srcType,
496 CompositeType.SrcNoEa,
497 dstType);
498 blit.Blit(srcData, dstData,
499 AlphaComposite.Src, null,
500 0, 0, 0, 0, w, h);
501 dstData.markDirty();
502 }
503
504 /**
505 * This is an alternate implementation for updating the cached
506 * SurfaceData from the source (primary) SurfaceData using a
507 * background color for transparent pixels.
508 * A simple BlitBg is used to copy the pixels from the source to
509 * the destination SurfaceData with the specified bgColor.
510 * A subclass can override the normal updateSurfaceData method
511 * and call this implementation instead if it wants to use color
512 * keying for bitmask images.
513 */
514 public void updateSurfaceDataBg(SurfaceData srcData,
515 SurfaceData dstData,
516 int w, int h, Color bgColor)
517 {
518 SurfaceType srcType = srcData.getSurfaceType();
519 SurfaceType dstType = dstData.getSurfaceType();
520 BlitBg blitbg = BlitBg.getFromCache(srcType,
521 CompositeType.SrcNoEa,
522 dstType);
523 blitbg.BlitBg(srcData, dstData,
524 AlphaComposite.Src, null, bgColor.getRGB(),
525 0, 0, 0, 0, w, h);
526 dstData.markDirty();
527 }
528}