Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/java2d/SurfaceDataProxy.java
38829 views
1
/*
2
* Copyright (c) 2007, 2013, 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;
27
28
import java.awt.Color;
29
import java.awt.Rectangle;
30
import java.awt.AlphaComposite;
31
import java.awt.GraphicsEnvironment;
32
33
import sun.awt.DisplayChangedListener;
34
import sun.java2d.StateTrackable.State;
35
import sun.java2d.loops.CompositeType;
36
import sun.java2d.loops.SurfaceType;
37
import sun.java2d.loops.Blit;
38
import sun.java2d.loops.BlitBg;
39
import sun.awt.image.SurfaceManager;
40
import sun.awt.image.SurfaceManager.FlushableCacheData;
41
42
import java.security.AccessController;
43
import 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
*/
66
public 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 = 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 = 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 occurred 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
}
529
530