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