Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/sun/java2d/pipe/BufferedContext.java
41159 views
1
/*
2
* Copyright (c) 2005, 2019, 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.pipe;
27
28
import java.awt.AlphaComposite;
29
import java.awt.Color;
30
import java.awt.Composite;
31
import java.awt.Paint;
32
import java.awt.geom.AffineTransform;
33
import java.lang.annotation.Native;
34
import java.lang.ref.Reference;
35
import java.lang.ref.WeakReference;
36
37
import sun.java2d.InvalidPipeException;
38
import sun.java2d.SunGraphics2D;
39
import sun.java2d.loops.XORComposite;
40
import sun.java2d.pipe.hw.AccelSurface;
41
42
import static sun.java2d.pipe.BufferedOpCodes.BEGIN_SHAPE_CLIP;
43
import static sun.java2d.pipe.BufferedOpCodes.END_SHAPE_CLIP;
44
import static sun.java2d.pipe.BufferedOpCodes.RESET_CLIP;
45
import static sun.java2d.pipe.BufferedOpCodes.RESET_COMPOSITE;
46
import static sun.java2d.pipe.BufferedOpCodes.RESET_TRANSFORM;
47
import static sun.java2d.pipe.BufferedOpCodes.SET_ALPHA_COMPOSITE;
48
import static sun.java2d.pipe.BufferedOpCodes.SET_RECT_CLIP;
49
import static sun.java2d.pipe.BufferedOpCodes.SET_SHAPE_CLIP_SPANS;
50
import static sun.java2d.pipe.BufferedOpCodes.SET_SURFACES;
51
import static sun.java2d.pipe.BufferedOpCodes.SET_TRANSFORM;
52
import static sun.java2d.pipe.BufferedOpCodes.SET_XOR_COMPOSITE;
53
import static sun.java2d.pipe.BufferedRenderPipe.BYTES_PER_SPAN;
54
55
/**
56
* Base context class for managing state in a single-threaded rendering
57
* environment. Each state-setting operation (e.g. SET_COLOR) is added to
58
* the provided RenderQueue, which will be processed at a later time by a
59
* single thread. Note that the RenderQueue lock must be acquired before
60
* calling the validate() method (or any other method in this class). See
61
* the RenderQueue class comments for a sample usage scenario.
62
*
63
* @see RenderQueue
64
*/
65
public abstract class BufferedContext {
66
67
/*
68
* The following flags help the internals of validate() determine
69
* the appropriate (meaning correct, or optimal) code path when
70
* setting up the current context. The flags can be bitwise OR'd
71
* together as needed.
72
*/
73
74
/**
75
* Indicates that no flags are needed; take all default code paths.
76
*/
77
@Native public static final int NO_CONTEXT_FLAGS = (0 << 0);
78
/**
79
* Indicates that the source surface (or color value, if it is a simple
80
* rendering operation) is opaque (has an alpha value of 1.0). If this
81
* flag is present, it allows us to disable blending in certain
82
* situations in order to improve performance.
83
*/
84
@Native public static final int SRC_IS_OPAQUE = (1 << 0);
85
/**
86
* Indicates that the operation uses an alpha mask, which may determine
87
* the code path that is used when setting up the current paint state.
88
*/
89
@Native public static final int USE_MASK = (1 << 1);
90
91
private final RenderQueue rq;
92
private final RenderBuffer buf;
93
94
/**
95
* This is a reference to the most recently validated BufferedContext. If
96
* this value is null, it means that there is no current context. It is
97
* provided here so that validate() only needs to do a quick reference
98
* check to see if the BufferedContext passed to that method is the same
99
* as the one we've cached here.
100
*/
101
protected static BufferedContext currentContext;
102
103
private Reference<AccelSurface> validSrcDataRef = new WeakReference<>(null);
104
private Reference<AccelSurface> validDstDataRef = new WeakReference<>(null);
105
private Reference<Region> validClipRef = new WeakReference<>(null);
106
private Reference<Composite> validCompRef = new WeakReference<>(null);
107
private Reference<Paint> validPaintRef = new WeakReference<>(null);
108
// renamed from isValidatedPaintAColor as part of a work around for 6764257
109
private boolean isValidatedPaintJustAColor;
110
private int validatedRGB;
111
private int validatedFlags;
112
private boolean xformInUse;
113
private AffineTransform transform;
114
115
protected BufferedContext(RenderQueue rq) {
116
this.rq = rq;
117
this.buf = rq.getBuffer();
118
}
119
120
/**
121
* Fetches the BufferedContextContext associated with the dst. surface
122
* and validates the context using the given parameters. Most rendering
123
* operations will call this method first in order to set the necessary
124
* state before issuing rendering commands.
125
*
126
* Note: must be called while the RenderQueue lock is held.
127
*
128
* It's assumed that the type of surfaces has been checked by the Renderer
129
*
130
* @throws InvalidPipeException if either src or dest surface is not valid
131
* or lost
132
* @see RenderQueue#lock
133
* @see RenderQueue#unlock
134
*/
135
public static void validateContext(AccelSurface srcData,
136
AccelSurface dstData,
137
Region clip, Composite comp,
138
AffineTransform xform,
139
Paint paint, SunGraphics2D sg2d,
140
int flags)
141
{
142
// assert rq.lock.isHeldByCurrentThread();
143
BufferedContext context = dstData.getContext();
144
context.validate(srcData, dstData,
145
clip, comp, xform, paint, sg2d, flags);
146
}
147
148
/**
149
* Fetches the BufferedContextassociated with the surface
150
* and disables all context state settings.
151
*
152
* Note: must be called while the RenderQueue lock is held.
153
*
154
* It's assumed that the type of surfaces has been checked by the Renderer
155
*
156
* @throws InvalidPipeException if the surface is not valid
157
* or lost
158
* @see RenderQueue#lock
159
* @see RenderQueue#unlock
160
*/
161
public static void validateContext(AccelSurface surface) {
162
// assert rt.lock.isHeldByCurrentThread();
163
validateContext(surface, surface,
164
null, null, null, null, null, NO_CONTEXT_FLAGS);
165
}
166
167
/**
168
* Validates the given parameters against the current state for this
169
* context. If this context is not current, it will be made current
170
* for the given source and destination surfaces, and the viewport will
171
* be updated. Then each part of the context state (clip, composite,
172
* etc.) is checked against the previous value. If the value has changed
173
* since the last call to validate(), it will be updated accordingly.
174
*
175
* Note that the SunGraphics2D parameter is only used for the purposes
176
* of validating a (non-null) Paint parameter. In all other cases it
177
* is safe to pass a null SunGraphics2D and it will be ignored.
178
*
179
* Note: must be called while the RenderQueue lock is held.
180
*
181
* It's assumed that the type of surfaces has been checked by the Renderer
182
*
183
* @throws InvalidPipeException if either src or dest surface is not valid
184
* or lost
185
*/
186
private void validate(AccelSurface srcData, AccelSurface dstData,
187
Region clip, Composite comp,
188
AffineTransform xform,
189
Paint paint, SunGraphics2D sg2d, int flags)
190
{
191
// assert rq.lock.isHeldByCurrentThread();
192
193
boolean updateClip = false;
194
boolean updatePaint = false;
195
196
if (!dstData.isValid() ||
197
dstData.isSurfaceLost() || srcData.isSurfaceLost())
198
{
199
invalidateContext();
200
throw new InvalidPipeException("bounds changed or surface lost");
201
}
202
203
if (paint instanceof Color) {
204
// REMIND: not 30-bit friendly
205
int newRGB = ((Color)paint).getRGB();
206
if (isValidatedPaintJustAColor) {
207
if (newRGB != validatedRGB) {
208
validatedRGB = newRGB;
209
updatePaint = true;
210
}
211
} else {
212
validatedRGB = newRGB;
213
updatePaint = true;
214
isValidatedPaintJustAColor = true;
215
}
216
} else if (validPaintRef.get() != paint) {
217
updatePaint = true;
218
// this should be set when we are switching from paint to color
219
// in which case this condition will be true
220
isValidatedPaintJustAColor = false;
221
}
222
223
final AccelSurface validatedSrcData = validSrcDataRef.get();
224
final AccelSurface validatedDstData = validDstDataRef.get();
225
if ((currentContext != this) ||
226
(srcData != validatedSrcData) ||
227
(dstData != validatedDstData))
228
{
229
if (dstData != validatedDstData) {
230
// the clip is dependent on the destination surface, so we
231
// need to update it if we have a new destination surface
232
updateClip = true;
233
}
234
235
if (paint == null) {
236
// make sure we update the color state (otherwise, it might
237
// not be updated if this is the first time the context
238
// is being validated)
239
updatePaint = true;
240
}
241
242
// update the current source and destination surfaces
243
setSurfaces(srcData, dstData);
244
245
currentContext = this;
246
validSrcDataRef = new WeakReference<>(srcData);
247
validDstDataRef = new WeakReference<>(dstData);
248
}
249
250
// validate clip
251
final Region validatedClip = validClipRef.get();
252
if ((clip != validatedClip) || updateClip) {
253
if (clip != null) {
254
if (updateClip ||
255
validatedClip == null ||
256
!(validatedClip.isRectangular() && clip.isRectangular()) ||
257
((clip.getLoX() != validatedClip.getLoX() ||
258
clip.getLoY() != validatedClip.getLoY() ||
259
clip.getHiX() != validatedClip.getHiX() ||
260
clip.getHiY() != validatedClip.getHiY())))
261
{
262
setClip(clip);
263
}
264
} else {
265
resetClip();
266
}
267
validClipRef = new WeakReference<>(clip);
268
}
269
270
// validate composite (note that a change in the context flags
271
// may require us to update the composite state, even if the
272
// composite has not changed)
273
if ((comp != validCompRef.get()) || (flags != validatedFlags)) {
274
if (comp != null) {
275
setComposite(comp, flags);
276
} else {
277
resetComposite();
278
}
279
// the paint state is dependent on the composite state, so make
280
// sure we update the color below
281
updatePaint = true;
282
validCompRef = new WeakReference<>(comp);
283
validatedFlags = flags;
284
}
285
286
// validate transform
287
boolean txChanged = false;
288
if (xform == null) {
289
if (xformInUse) {
290
resetTransform();
291
xformInUse = false;
292
txChanged = true;
293
} else if (sg2d != null && !sg2d.transform.equals(transform)) {
294
txChanged = true;
295
}
296
if (sg2d != null && txChanged) {
297
transform = new AffineTransform(sg2d.transform);
298
}
299
} else {
300
setTransform(xform);
301
xformInUse = true;
302
txChanged = true;
303
}
304
// non-Color paints may require paint revalidation
305
if (!isValidatedPaintJustAColor && txChanged) {
306
updatePaint = true;
307
}
308
309
// validate paint
310
if (updatePaint) {
311
if (paint != null) {
312
BufferedPaints.setPaint(rq, sg2d, paint, flags);
313
} else {
314
BufferedPaints.resetPaint(rq);
315
}
316
validPaintRef = new WeakReference<>(paint);
317
}
318
319
// mark dstData dirty
320
// REMIND: is this really needed now? we do it in SunGraphics2D..
321
dstData.markDirty();
322
}
323
324
private void setSurfaces(AccelSurface srcData,
325
AccelSurface dstData)
326
{
327
// assert rq.lock.isHeldByCurrentThread();
328
rq.ensureCapacityAndAlignment(20, 4);
329
buf.putInt(SET_SURFACES);
330
buf.putLong(srcData.getNativeOps());
331
buf.putLong(dstData.getNativeOps());
332
}
333
334
private void resetClip() {
335
// assert rq.lock.isHeldByCurrentThread();
336
rq.ensureCapacity(4);
337
buf.putInt(RESET_CLIP);
338
}
339
340
private void setClip(Region clip) {
341
// assert rq.lock.isHeldByCurrentThread();
342
if (clip.isRectangular()) {
343
rq.ensureCapacity(20);
344
buf.putInt(SET_RECT_CLIP);
345
buf.putInt(clip.getLoX()).putInt(clip.getLoY());
346
buf.putInt(clip.getHiX()).putInt(clip.getHiY());
347
} else {
348
rq.ensureCapacity(28); // so that we have room for at least a span
349
buf.putInt(BEGIN_SHAPE_CLIP);
350
buf.putInt(SET_SHAPE_CLIP_SPANS);
351
// include a placeholder for the span count
352
int countIndex = buf.position();
353
buf.putInt(0);
354
int spanCount = 0;
355
int remainingSpans = buf.remaining() / BYTES_PER_SPAN;
356
int[] span = new int[4];
357
SpanIterator si = clip.getSpanIterator();
358
while (si.nextSpan(span)) {
359
if (remainingSpans == 0) {
360
buf.putInt(countIndex, spanCount);
361
rq.flushNow();
362
buf.putInt(SET_SHAPE_CLIP_SPANS);
363
countIndex = buf.position();
364
buf.putInt(0);
365
spanCount = 0;
366
remainingSpans = buf.remaining() / BYTES_PER_SPAN;
367
}
368
buf.putInt(span[0]); // x1
369
buf.putInt(span[1]); // y1
370
buf.putInt(span[2]); // x2
371
buf.putInt(span[3]); // y2
372
spanCount++;
373
remainingSpans--;
374
}
375
buf.putInt(countIndex, spanCount);
376
rq.ensureCapacity(4);
377
buf.putInt(END_SHAPE_CLIP);
378
}
379
}
380
381
private void resetComposite() {
382
// assert rq.lock.isHeldByCurrentThread();
383
rq.ensureCapacity(4);
384
buf.putInt(RESET_COMPOSITE);
385
}
386
387
private void setComposite(Composite comp, int flags) {
388
// assert rq.lock.isHeldByCurrentThread();
389
if (comp instanceof AlphaComposite) {
390
AlphaComposite ac = (AlphaComposite)comp;
391
rq.ensureCapacity(16);
392
buf.putInt(SET_ALPHA_COMPOSITE);
393
buf.putInt(ac.getRule());
394
buf.putFloat(ac.getAlpha());
395
buf.putInt(flags);
396
} else if (comp instanceof XORComposite) {
397
int xorPixel = ((XORComposite)comp).getXorPixel();
398
rq.ensureCapacity(8);
399
buf.putInt(SET_XOR_COMPOSITE);
400
buf.putInt(xorPixel);
401
} else {
402
throw new InternalError("not yet implemented");
403
}
404
}
405
406
private void resetTransform() {
407
// assert rq.lock.isHeldByCurrentThread();
408
rq.ensureCapacity(4);
409
buf.putInt(RESET_TRANSFORM);
410
}
411
412
private void setTransform(AffineTransform xform) {
413
// assert rq.lock.isHeldByCurrentThread();
414
rq.ensureCapacityAndAlignment(52, 4);
415
buf.putInt(SET_TRANSFORM);
416
buf.putDouble(xform.getScaleX());
417
buf.putDouble(xform.getShearY());
418
buf.putDouble(xform.getShearX());
419
buf.putDouble(xform.getScaleY());
420
buf.putDouble(xform.getTranslateX());
421
buf.putDouble(xform.getTranslateY());
422
}
423
424
/**
425
* Resets this context's surfaces and all attributes.
426
*
427
* Note: must be called while the RenderQueue lock is held.
428
*
429
* @see RenderQueue#lock
430
* @see RenderQueue#unlock
431
*/
432
public final void invalidateContext() {
433
resetTransform();
434
resetComposite();
435
resetClip();
436
BufferedPaints.resetPaint(rq);
437
validSrcDataRef.clear();
438
validDstDataRef.clear();
439
validCompRef.clear();
440
validClipRef.clear();
441
validPaintRef.clear();
442
isValidatedPaintJustAColor = false;
443
xformInUse = false;
444
}
445
446
/**
447
* Returns a singleton {@code RenderQueue} object used by the rendering
448
* pipeline.
449
*
450
* @return a render queue
451
* @see RenderQueue
452
*/
453
public final RenderQueue getRenderQueue() {
454
return rq;
455
}
456
}
457
458