1 /*
2 * Copyright (c) 2005, 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.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 sun.java2d.pipe.hw.AccelSurface;
34 import sun.java2d.InvalidPipeException;
35 import sun.java2d.SunGraphics2D;
36 import sun.java2d.loops.XORComposite;
37 import static sun.java2d.pipe.BufferedOpCodes.*;
38 import static sun.java2d.pipe.BufferedRenderPipe.BYTES_PER_SPAN;
39
40 import java.lang.annotation.Native;
41
42 /**
43 * Base context class for managing state in a single-threaded rendering
44 * environment. Each state-setting operation (e.g. SET_COLOR) is added to
45 * the provided RenderQueue, which will be processed at a later time by a
46 * single thread. Note that the RenderQueue lock must be acquired before
47 * calling the validate() method (or any other method in this class). See
48 * the RenderQueue class comments for a sample usage scenario.
49 *
50 * @see RenderQueue
51 */
52 public abstract class BufferedContext {
53
54 /*
55 * The following flags help the internals of validate() determine
56 * the appropriate (meaning correct, or optimal) code path when
57 * setting up the current context. The flags can be bitwise OR'd
58 * together as needed.
59 */
60
70 */
71 @Native public static final int SRC_IS_OPAQUE = (1 << 0);
72 /**
73 * Indicates that the operation uses an alpha mask, which may determine
74 * the code path that is used when setting up the current paint state.
75 */
76 @Native public static final int USE_MASK = (1 << 1);
77
78 protected RenderQueue rq;
79 protected RenderBuffer buf;
80
81 /**
82 * This is a reference to the most recently validated BufferedContext. If
83 * this value is null, it means that there is no current context. It is
84 * provided here so that validate() only needs to do a quick reference
85 * check to see if the BufferedContext passed to that method is the same
86 * as the one we've cached here.
87 */
88 protected static BufferedContext currentContext;
89
90 private AccelSurface validatedSrcData;
91 private AccelSurface validatedDstData;
92 private Region validatedClip;
93 private Composite validatedComp;
94 private Paint validatedPaint;
95 // renamed from isValidatedPaintAColor as part of a work around for 6764257
96 private boolean isValidatedPaintJustAColor;
97 private int validatedRGB;
98 private int validatedFlags;
99 private boolean xformInUse;
100 private AffineTransform transform;
101
102 protected BufferedContext(RenderQueue rq) {
103 this.rq = rq;
104 this.buf = rq.getBuffer();
105 }
106
107 /**
108 * Fetches the BufferedContextContext associated with the dst. surface
109 * and validates the context using the given parameters. Most rendering
110 * operations will call this method first in order to set the necessary
111 * state before issuing rendering commands.
112 *
113 * Note: must be called while the RenderQueue lock is held.
114 *
115 * It's assumed that the type of surfaces has been checked by the Renderer
116 *
117 * @throws InvalidPipeException if either src or dest surface is not valid
118 * or lost
119 * @see RenderQueue#lock
120 * @see RenderQueue#unlock
121 */
122 public static void validateContext(AccelSurface srcData,
123 AccelSurface dstData,
124 Region clip, Composite comp,
125 AffineTransform xform,
126 Paint paint, SunGraphics2D sg2d,
127 int flags)
128 {
129 // assert rq.lock.isHeldByCurrentThread();
130 BufferedContext d3dc = dstData.getContext();
131 d3dc.validate(srcData, dstData,
132 clip, comp, xform, paint, sg2d, flags);
133 }
134
135 /**
136 * Fetches the BufferedContextassociated with the surface
137 * and disables all context state settings.
138 *
139 * Note: must be called while the RenderQueue lock is held.
140 *
141 * It's assumed that the type of surfaces has been checked by the Renderer
142 *
143 * @throws InvalidPipeException if the surface is not valid
144 * or lost
145 * @see RenderQueue#lock
146 * @see RenderQueue#unlock
147 */
148 public static void validateContext(AccelSurface surface) {
149 // assert rt.lock.isHeldByCurrentThread();
150 validateContext(surface, surface,
151 null, null, null, null, null, NO_CONTEXT_FLAGS);
183 if (!dstData.isValid() ||
184 dstData.isSurfaceLost() || srcData.isSurfaceLost())
185 {
186 invalidateContext();
187 throw new InvalidPipeException("bounds changed or surface lost");
188 }
189
190 if (paint instanceof Color) {
191 // REMIND: not 30-bit friendly
192 int newRGB = ((Color)paint).getRGB();
193 if (isValidatedPaintJustAColor) {
194 if (newRGB != validatedRGB) {
195 validatedRGB = newRGB;
196 updatePaint = true;
197 }
198 } else {
199 validatedRGB = newRGB;
200 updatePaint = true;
201 isValidatedPaintJustAColor = true;
202 }
203 } else if (validatedPaint != paint) {
204 updatePaint = true;
205 // this should be set when we are switching from paint to color
206 // in which case this condition will be true
207 isValidatedPaintJustAColor = false;
208 }
209
210 if ((currentContext != this) ||
211 (srcData != validatedSrcData) ||
212 (dstData != validatedDstData))
213 {
214 if (dstData != validatedDstData) {
215 // the clip is dependent on the destination surface, so we
216 // need to update it if we have a new destination surface
217 updateClip = true;
218 }
219
220 if (paint == null) {
221 // make sure we update the color state (otherwise, it might
222 // not be updated if this is the first time the context
223 // is being validated)
224 updatePaint = true;
225 }
226
227 // update the current source and destination surfaces
228 setSurfaces(srcData, dstData);
229
230 currentContext = this;
231 validatedSrcData = srcData;
232 validatedDstData = dstData;
233 }
234
235 // validate clip
236 if ((clip != validatedClip) || updateClip) {
237 if (clip != null) {
238 if (updateClip ||
239 validatedClip == null ||
240 !(validatedClip.isRectangular() && clip.isRectangular()) ||
241 ((clip.getLoX() != validatedClip.getLoX() ||
242 clip.getLoY() != validatedClip.getLoY() ||
243 clip.getHiX() != validatedClip.getHiX() ||
244 clip.getHiY() != validatedClip.getHiY())))
245 {
246 setClip(clip);
247 }
248 } else {
249 resetClip();
250 }
251 validatedClip = clip;
252 }
253
254 // validate composite (note that a change in the context flags
255 // may require us to update the composite state, even if the
256 // composite has not changed)
257 if ((comp != validatedComp) || (flags != validatedFlags)) {
258 if (comp != null) {
259 setComposite(comp, flags);
260 } else {
261 resetComposite();
262 }
263 // the paint state is dependent on the composite state, so make
264 // sure we update the color below
265 updatePaint = true;
266 validatedComp = comp;
267 validatedFlags = flags;
268 }
269
270 // validate transform
271 boolean txChanged = false;
272 if (xform == null) {
273 if (xformInUse) {
274 resetTransform();
275 xformInUse = false;
276 txChanged = true;
277 } else if (sg2d != null && !sg2d.transform.equals(transform)) {
278 txChanged = true;
279 }
280 if (sg2d != null && txChanged) {
281 transform = new AffineTransform(sg2d.transform);
282 }
283 } else {
284 setTransform(xform);
285 xformInUse = true;
286 txChanged = true;
287 }
288 // non-Color paints may require paint revalidation
289 if (!isValidatedPaintJustAColor && txChanged) {
290 updatePaint = true;
291 }
292
293 // validate paint
294 if (updatePaint) {
295 if (paint != null) {
296 BufferedPaints.setPaint(rq, sg2d, paint, flags);
297 } else {
298 BufferedPaints.resetPaint(rq);
299 }
300 validatedPaint = paint;
301 }
302
303 // mark dstData dirty
304 // REMIND: is this really needed now? we do it in SunGraphics2D..
305 dstData.markDirty();
306 }
307
308 /**
309 * Invalidates the surfaces associated with this context. This is
310 * useful when the context is no longer needed, and we want to break
311 * the chain caused by these surface references.
312 *
313 * Note: must be called while the RenderQueue lock is held.
314 *
315 * @see RenderQueue#lock
316 * @see RenderQueue#unlock
317 */
318 public void invalidateSurfaces() {
319 validatedSrcData = null;
320 validatedDstData = null;
321 }
322
323 private void setSurfaces(AccelSurface srcData,
324 AccelSurface dstData)
325 {
326 // assert rq.lock.isHeldByCurrentThread();
327 rq.ensureCapacityAndAlignment(20, 4);
328 buf.putInt(SET_SURFACES);
329 buf.putLong(srcData.getNativeOps());
330 buf.putLong(dstData.getNativeOps());
331 }
332
333 private void resetClip() {
334 // assert rq.lock.isHeldByCurrentThread();
335 rq.ensureCapacity(4);
336 buf.putInt(RESET_CLIP);
337 }
338
339 private void setClip(Region clip) {
340 // assert rq.lock.isHeldByCurrentThread();
417 buf.putDouble(xform.getShearX());
418 buf.putDouble(xform.getScaleY());
419 buf.putDouble(xform.getTranslateX());
420 buf.putDouble(xform.getTranslateY());
421 }
422
423 /**
424 * Resets this context's surfaces and all attributes.
425 *
426 * Note: must be called while the RenderQueue lock is held.
427 *
428 * @see RenderQueue#lock
429 * @see RenderQueue#unlock
430 */
431 public void invalidateContext() {
432 resetTransform();
433 resetComposite();
434 resetClip();
435 BufferedPaints.resetPaint(rq);
436 invalidateSurfaces();
437 validatedComp = null;
438 validatedClip = null;
439 validatedPaint = null;
440 isValidatedPaintJustAColor = false;
441 xformInUse = false;
442 }
443
444 /**
445 * Returns a singleton {@code RenderQueue} object used by the rendering
446 * pipeline.
447 *
448 * @return a render queue
449 * @see RenderQueue
450 */
451 public abstract RenderQueue getRenderQueue();
452
453 /**
454 * Saves the state of this context.
455 * It may reset the current context.
456 *
457 * Note: must be called while the RenderQueue lock is held.
458 *
459 * @see RenderQueue#lock
|
1 /*
2 * Copyright (c) 2005, 2016, 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 sun.java2d.pipe.hw.AccelSurface;
34 import sun.java2d.InvalidPipeException;
35 import sun.java2d.SunGraphics2D;
36 import sun.java2d.loops.XORComposite;
37 import static sun.java2d.pipe.BufferedOpCodes.*;
38 import static sun.java2d.pipe.BufferedRenderPipe.BYTES_PER_SPAN;
39
40 import java.lang.annotation.Native;
41 import java.lang.ref.Reference;
42 import java.lang.ref.WeakReference;
43
44 /**
45 * Base context class for managing state in a single-threaded rendering
46 * environment. Each state-setting operation (e.g. SET_COLOR) is added to
47 * the provided RenderQueue, which will be processed at a later time by a
48 * single thread. Note that the RenderQueue lock must be acquired before
49 * calling the validate() method (or any other method in this class). See
50 * the RenderQueue class comments for a sample usage scenario.
51 *
52 * @see RenderQueue
53 */
54 public abstract class BufferedContext {
55
56 /*
57 * The following flags help the internals of validate() determine
58 * the appropriate (meaning correct, or optimal) code path when
59 * setting up the current context. The flags can be bitwise OR'd
60 * together as needed.
61 */
62
72 */
73 @Native public static final int SRC_IS_OPAQUE = (1 << 0);
74 /**
75 * Indicates that the operation uses an alpha mask, which may determine
76 * the code path that is used when setting up the current paint state.
77 */
78 @Native public static final int USE_MASK = (1 << 1);
79
80 protected RenderQueue rq;
81 protected RenderBuffer buf;
82
83 /**
84 * This is a reference to the most recently validated BufferedContext. If
85 * this value is null, it means that there is no current context. It is
86 * provided here so that validate() only needs to do a quick reference
87 * check to see if the BufferedContext passed to that method is the same
88 * as the one we've cached here.
89 */
90 protected static BufferedContext currentContext;
91
92 private Reference<AccelSurface> validSrcDataRef = new WeakReference<>(null);
93 private Reference<AccelSurface> validDstDataRef = new WeakReference<>(null);
94 private Reference<Region> validClipRef = new WeakReference<>(null);
95 private Reference<Composite> validCompRef = new WeakReference<>(null);
96 private Reference<Paint> validPaintRef = new WeakReference<>(null);
97 // renamed from isValidatedPaintAColor as part of a work around for 6764257
98 private boolean isValidatedPaintJustAColor;
99 private int validatedRGB;
100 private int validatedFlags;
101 private boolean xformInUse;
102 private AffineTransform transform;
103
104 protected BufferedContext(RenderQueue rq) {
105 this.rq = rq;
106 this.buf = rq.getBuffer();
107 }
108
109 /**
110 * Fetches the BufferedContextContext associated with the dst. surface
111 * and validates the context using the given parameters. Most rendering
112 * operations will call this method first in order to set the necessary
113 * state before issuing rendering commands.
114 *
115 * Note: must be called while the RenderQueue lock is held.
116 *
117 * It's assumed that the type of surfaces has been checked by the Renderer
118 *
119 * @throws InvalidPipeException if either src or dest surface is not valid
120 * or lost
121 * @see RenderQueue#lock
122 * @see RenderQueue#unlock
123 */
124 public static void validateContext(AccelSurface srcData,
125 AccelSurface dstData,
126 Region clip, Composite comp,
127 AffineTransform xform,
128 Paint paint, SunGraphics2D sg2d,
129 int flags)
130 {
131 // assert rq.lock.isHeldByCurrentThread();
132 BufferedContext context = dstData.getContext();
133 context.validate(srcData, dstData,
134 clip, comp, xform, paint, sg2d, flags);
135 }
136
137 /**
138 * Fetches the BufferedContextassociated with the surface
139 * and disables all context state settings.
140 *
141 * Note: must be called while the RenderQueue lock is held.
142 *
143 * It's assumed that the type of surfaces has been checked by the Renderer
144 *
145 * @throws InvalidPipeException if the surface is not valid
146 * or lost
147 * @see RenderQueue#lock
148 * @see RenderQueue#unlock
149 */
150 public static void validateContext(AccelSurface surface) {
151 // assert rt.lock.isHeldByCurrentThread();
152 validateContext(surface, surface,
153 null, null, null, null, null, NO_CONTEXT_FLAGS);
185 if (!dstData.isValid() ||
186 dstData.isSurfaceLost() || srcData.isSurfaceLost())
187 {
188 invalidateContext();
189 throw new InvalidPipeException("bounds changed or surface lost");
190 }
191
192 if (paint instanceof Color) {
193 // REMIND: not 30-bit friendly
194 int newRGB = ((Color)paint).getRGB();
195 if (isValidatedPaintJustAColor) {
196 if (newRGB != validatedRGB) {
197 validatedRGB = newRGB;
198 updatePaint = true;
199 }
200 } else {
201 validatedRGB = newRGB;
202 updatePaint = true;
203 isValidatedPaintJustAColor = true;
204 }
205 } else if (validPaintRef.get() != paint) {
206 updatePaint = true;
207 // this should be set when we are switching from paint to color
208 // in which case this condition will be true
209 isValidatedPaintJustAColor = false;
210 }
211
212 final AccelSurface validatedSrcData = validSrcDataRef.get();
213 final AccelSurface validatedDstData = validDstDataRef.get();
214 if ((currentContext != this) ||
215 (srcData != validatedSrcData) ||
216 (dstData != validatedDstData))
217 {
218 if (dstData != validatedDstData) {
219 // the clip is dependent on the destination surface, so we
220 // need to update it if we have a new destination surface
221 updateClip = true;
222 }
223
224 if (paint == null) {
225 // make sure we update the color state (otherwise, it might
226 // not be updated if this is the first time the context
227 // is being validated)
228 updatePaint = true;
229 }
230
231 // update the current source and destination surfaces
232 setSurfaces(srcData, dstData);
233
234 currentContext = this;
235 validSrcDataRef = new WeakReference<>(srcData);
236 validDstDataRef = new WeakReference<>(dstData);
237 }
238
239 // validate clip
240 final Region validatedClip = validClipRef.get();
241 if ((clip != validatedClip) || updateClip) {
242 if (clip != null) {
243 if (updateClip ||
244 validatedClip == null ||
245 !(validatedClip.isRectangular() && clip.isRectangular()) ||
246 ((clip.getLoX() != validatedClip.getLoX() ||
247 clip.getLoY() != validatedClip.getLoY() ||
248 clip.getHiX() != validatedClip.getHiX() ||
249 clip.getHiY() != validatedClip.getHiY())))
250 {
251 setClip(clip);
252 }
253 } else {
254 resetClip();
255 }
256 validClipRef = new WeakReference<>(clip);
257 }
258
259 // validate composite (note that a change in the context flags
260 // may require us to update the composite state, even if the
261 // composite has not changed)
262 if ((comp != validCompRef.get()) || (flags != validatedFlags)) {
263 if (comp != null) {
264 setComposite(comp, flags);
265 } else {
266 resetComposite();
267 }
268 // the paint state is dependent on the composite state, so make
269 // sure we update the color below
270 updatePaint = true;
271 validCompRef = new WeakReference<>(comp);
272 validatedFlags = flags;
273 }
274
275 // validate transform
276 boolean txChanged = false;
277 if (xform == null) {
278 if (xformInUse) {
279 resetTransform();
280 xformInUse = false;
281 txChanged = true;
282 } else if (sg2d != null && !sg2d.transform.equals(transform)) {
283 txChanged = true;
284 }
285 if (sg2d != null && txChanged) {
286 transform = new AffineTransform(sg2d.transform);
287 }
288 } else {
289 setTransform(xform);
290 xformInUse = true;
291 txChanged = true;
292 }
293 // non-Color paints may require paint revalidation
294 if (!isValidatedPaintJustAColor && txChanged) {
295 updatePaint = true;
296 }
297
298 // validate paint
299 if (updatePaint) {
300 if (paint != null) {
301 BufferedPaints.setPaint(rq, sg2d, paint, flags);
302 } else {
303 BufferedPaints.resetPaint(rq);
304 }
305 validPaintRef = new WeakReference<>(paint);
306 }
307
308 // mark dstData dirty
309 // REMIND: is this really needed now? we do it in SunGraphics2D..
310 dstData.markDirty();
311 }
312
313 /**
314 * Invalidates the surfaces associated with this context. This is
315 * useful when the context is no longer needed, and we want to break
316 * the chain caused by these surface references.
317 *
318 * Note: must be called while the RenderQueue lock is held.
319 *
320 * @see RenderQueue#lock
321 * @see RenderQueue#unlock
322 */
323 private void invalidateSurfaces() {
324 validSrcDataRef.clear();
325 validDstDataRef.clear();
326 }
327
328 private void setSurfaces(AccelSurface srcData,
329 AccelSurface dstData)
330 {
331 // assert rq.lock.isHeldByCurrentThread();
332 rq.ensureCapacityAndAlignment(20, 4);
333 buf.putInt(SET_SURFACES);
334 buf.putLong(srcData.getNativeOps());
335 buf.putLong(dstData.getNativeOps());
336 }
337
338 private void resetClip() {
339 // assert rq.lock.isHeldByCurrentThread();
340 rq.ensureCapacity(4);
341 buf.putInt(RESET_CLIP);
342 }
343
344 private void setClip(Region clip) {
345 // assert rq.lock.isHeldByCurrentThread();
422 buf.putDouble(xform.getShearX());
423 buf.putDouble(xform.getScaleY());
424 buf.putDouble(xform.getTranslateX());
425 buf.putDouble(xform.getTranslateY());
426 }
427
428 /**
429 * Resets this context's surfaces and all attributes.
430 *
431 * Note: must be called while the RenderQueue lock is held.
432 *
433 * @see RenderQueue#lock
434 * @see RenderQueue#unlock
435 */
436 public void invalidateContext() {
437 resetTransform();
438 resetComposite();
439 resetClip();
440 BufferedPaints.resetPaint(rq);
441 invalidateSurfaces();
442 validCompRef.clear();
443 validClipRef.clear();
444 validPaintRef.clear();
445 isValidatedPaintJustAColor = false;
446 xformInUse = false;
447 }
448
449 /**
450 * Returns a singleton {@code RenderQueue} object used by the rendering
451 * pipeline.
452 *
453 * @return a render queue
454 * @see RenderQueue
455 */
456 public abstract RenderQueue getRenderQueue();
457
458 /**
459 * Saves the state of this context.
460 * It may reset the current context.
461 *
462 * Note: must be called while the RenderQueue lock is held.
463 *
464 * @see RenderQueue#lock
|