1 /* 2 * Copyright (c) 2005, 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 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 javax.tools.annotation.GenerateNativeHeader; 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 /* No native methods here, but the constants are needed in the supporting JNI code */ 53 @GenerateNativeHeader 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 63 /** 64 * Indicates that no flags are needed; take all default code paths. 65 */ 66 public static final int NO_CONTEXT_FLAGS = (0 << 0); 67 /** 68 * Indicates that the source surface (or color value, if it is a simple 69 * rendering operation) is opaque (has an alpha value of 1.0). If this 70 * flag is present, it allows us to disable blending in certain 71 * situations in order to improve performance. 72 */ 73 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 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 AccelSurface validatedSrcData; 93 private AccelSurface validatedDstData; 94 private Region validatedClip; 95 private Composite validatedComp; 96 private Paint validatedPaint; 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 int transX; 103 private int transY; 104 105 protected BufferedContext(RenderQueue rq) { 106 this.rq = rq; 107 this.buf = rq.getBuffer(); 108 } 109 110 /** 111 * Fetches the BufferedContextContext associated with the dst. surface 112 * and validates the context using the given parameters. Most rendering 113 * operations will call this method first in order to set the necessary 114 * state before issuing rendering commands. 115 * 116 * Note: must be called while the RenderQueue lock is held. 117 * 118 * It's assumed that the type of surfaces has been checked by the Renderer 119 * 120 * @throws InvalidPipeException if either src or dest surface is not valid 121 * or lost 122 * @see RenderQueue#lock 123 * @see RenderQueue#unlock 124 */ 125 public static void validateContext(AccelSurface srcData, 126 AccelSurface dstData, 127 Region clip, Composite comp, 128 AffineTransform xform, 129 Paint paint, SunGraphics2D sg2d, 130 int flags) 131 { 132 // assert rq.lock.isHeldByCurrentThread(); 133 BufferedContext d3dc = dstData.getContext(); 134 d3dc.validate(srcData, dstData, 135 clip, comp, xform, paint, sg2d, flags); 136 } 137 138 /** 139 * Fetches the BufferedContextassociated with the surface 140 * and disables all context state settings. 141 * 142 * Note: must be called while the RenderQueue lock is held. 143 * 144 * It's assumed that the type of surfaces has been checked by the Renderer 145 * 146 * @throws InvalidPipeException if the surface is not valid 147 * or lost 148 * @see RenderQueue#lock 149 * @see RenderQueue#unlock 150 */ 151 public static void validateContext(AccelSurface surface) { 152 // assert rt.lock.isHeldByCurrentThread(); 153 validateContext(surface, surface, 154 null, null, null, null, null, NO_CONTEXT_FLAGS); 155 } 156 157 /** 158 * Validates the given parameters against the current state for this 159 * context. If this context is not current, it will be made current 160 * for the given source and destination surfaces, and the viewport will 161 * be updated. Then each part of the context state (clip, composite, 162 * etc.) is checked against the previous value. If the value has changed 163 * since the last call to validate(), it will be updated accordingly. 164 * 165 * Note that the SunGraphics2D parameter is only used for the purposes 166 * of validating a (non-null) Paint parameter. In all other cases it 167 * is safe to pass a null SunGraphics2D and it will be ignored. 168 * 169 * Note: must be called while the RenderQueue lock is held. 170 * 171 * It's assumed that the type of surfaces has been checked by the Renderer 172 * 173 * @throws InvalidPipeException if either src or dest surface is not valid 174 * or lost 175 */ 176 public void validate(AccelSurface srcData, AccelSurface dstData, 177 Region clip, Composite comp, 178 AffineTransform xform, 179 Paint paint, SunGraphics2D sg2d, int flags) 180 { 181 // assert rq.lock.isHeldByCurrentThread(); 182 183 boolean updateClip = false; 184 boolean updatePaint = false; 185 186 if (!dstData.isValid() || 187 dstData.isSurfaceLost() || srcData.isSurfaceLost()) 188 { 189 invalidateContext(); 190 throw new InvalidPipeException("bounds changed or surface lost"); 191 } 192 193 if (paint instanceof Color) { 194 // REMIND: not 30-bit friendly 195 int newRGB = ((Color)paint).getRGB(); 196 if (isValidatedPaintJustAColor) { 197 if (newRGB != validatedRGB) { 198 validatedRGB = newRGB; 199 updatePaint = true; 200 } 201 } else { 202 validatedRGB = newRGB; 203 updatePaint = true; 204 isValidatedPaintJustAColor = true; 205 } 206 } else if (validatedPaint != paint) { 207 updatePaint = true; 208 // this should be set when we are switching from paint to color 209 // in which case this condition will be true 210 isValidatedPaintJustAColor = false; 211 } 212 213 if ((currentContext != this) || 214 (srcData != validatedSrcData) || 215 (dstData != validatedDstData)) 216 { 217 if (dstData != validatedDstData) { 218 // the clip is dependent on the destination surface, so we 219 // need to update it if we have a new destination surface 220 updateClip = true; 221 } 222 223 if (paint == null) { 224 // make sure we update the color state (otherwise, it might 225 // not be updated if this is the first time the context 226 // is being validated) 227 updatePaint = true; 228 } 229 230 // update the current source and destination surfaces 231 setSurfaces(srcData, dstData); 232 233 currentContext = this; 234 validatedSrcData = srcData; 235 validatedDstData = dstData; 236 } 237 238 // validate clip 239 if ((clip != validatedClip) || updateClip) { 240 if (clip != null) { 241 if (updateClip || 242 validatedClip == null || 243 !(validatedClip.isRectangular() && clip.isRectangular()) || 244 ((clip.getLoX() != validatedClip.getLoX() || 245 clip.getLoY() != validatedClip.getLoY() || 246 clip.getHiX() != validatedClip.getHiX() || 247 clip.getHiY() != validatedClip.getHiY()))) 248 { 249 setClip(clip); 250 } 251 } else { 252 resetClip(); 253 } 254 validatedClip = clip; 255 } 256 257 // validate composite (note that a change in the context flags 258 // may require us to update the composite state, even if the 259 // composite has not changed) 260 if ((comp != validatedComp) || (flags != validatedFlags)) { 261 if (comp != null) { 262 setComposite(comp, flags); 263 } else { 264 resetComposite(); 265 } 266 // the paint state is dependent on the composite state, so make 267 // sure we update the color below 268 updatePaint = true; 269 validatedComp = comp; 270 validatedFlags = flags; 271 } 272 273 // validate transform 274 boolean txChanged = false; 275 if (xform == null) { 276 if (xformInUse) { 277 resetTransform(); 278 xformInUse = false; 279 txChanged = true; 280 } else if (sg2d != null) { 281 if (transX != sg2d.transX || transY != sg2d.transY) { 282 txChanged = true; 283 } 284 } 285 if (sg2d != null) { 286 transX = sg2d.transX; 287 transY = sg2d.transY; 288 } 289 } else { 290 setTransform(xform); 291 xformInUse = true; 292 txChanged = true; 293 } 294 // non-Color paints may require paint revalidation 295 if (!isValidatedPaintJustAColor && txChanged) { 296 updatePaint = true; 297 } 298 299 // validate paint 300 if (updatePaint) { 301 if (paint != null) { 302 BufferedPaints.setPaint(rq, sg2d, paint, flags); 303 } else { 304 BufferedPaints.resetPaint(rq); 305 } 306 validatedPaint = paint; 307 } 308 309 // mark dstData dirty 310 // REMIND: is this really needed now? we do it in SunGraphics2D.. 311 dstData.markDirty(); 312 } 313 314 /** 315 * Invalidates the surfaces associated with this context. This is 316 * useful when the context is no longer needed, and we want to break 317 * the chain caused by these surface references. 318 * 319 * Note: must be called while the RenderQueue lock is held. 320 * 321 * @see RenderQueue#lock 322 * @see RenderQueue#unlock 323 */ 324 public void invalidateSurfaces() { 325 validatedSrcData = null; 326 validatedDstData = null; 327 } 328 329 private void setSurfaces(AccelSurface srcData, 330 AccelSurface dstData) 331 { 332 // assert rq.lock.isHeldByCurrentThread(); 333 rq.ensureCapacityAndAlignment(20, 4); 334 buf.putInt(SET_SURFACES); 335 buf.putLong(srcData.getNativeOps()); 336 buf.putLong(dstData.getNativeOps()); 337 } 338 339 private void resetClip() { 340 // assert rq.lock.isHeldByCurrentThread(); 341 rq.ensureCapacity(4); 342 buf.putInt(RESET_CLIP); 343 } 344 345 private void setClip(Region clip) { 346 // assert rq.lock.isHeldByCurrentThread(); 347 if (clip.isRectangular()) { 348 rq.ensureCapacity(20); 349 buf.putInt(SET_RECT_CLIP); 350 buf.putInt(clip.getLoX()).putInt(clip.getLoY()); 351 buf.putInt(clip.getHiX()).putInt(clip.getHiY()); 352 } else { 353 rq.ensureCapacity(28); // so that we have room for at least a span 354 buf.putInt(BEGIN_SHAPE_CLIP); 355 buf.putInt(SET_SHAPE_CLIP_SPANS); 356 // include a placeholder for the span count 357 int countIndex = buf.position(); 358 buf.putInt(0); 359 int spanCount = 0; 360 int remainingSpans = buf.remaining() / BYTES_PER_SPAN; 361 int span[] = new int[4]; 362 SpanIterator si = clip.getSpanIterator(); 363 while (si.nextSpan(span)) { 364 if (remainingSpans == 0) { 365 buf.putInt(countIndex, spanCount); 366 rq.flushNow(); 367 buf.putInt(SET_SHAPE_CLIP_SPANS); 368 countIndex = buf.position(); 369 buf.putInt(0); 370 spanCount = 0; 371 remainingSpans = buf.remaining() / BYTES_PER_SPAN; 372 } 373 buf.putInt(span[0]); // x1 374 buf.putInt(span[1]); // y1 375 buf.putInt(span[2]); // x2 376 buf.putInt(span[3]); // y2 377 spanCount++; 378 remainingSpans--; 379 } 380 buf.putInt(countIndex, spanCount); 381 rq.ensureCapacity(4); 382 buf.putInt(END_SHAPE_CLIP); 383 } 384 } 385 386 private void resetComposite() { 387 // assert rq.lock.isHeldByCurrentThread(); 388 rq.ensureCapacity(4); 389 buf.putInt(RESET_COMPOSITE); 390 } 391 392 private void setComposite(Composite comp, int flags) { 393 // assert rq.lock.isHeldByCurrentThread(); 394 if (comp instanceof AlphaComposite) { 395 AlphaComposite ac = (AlphaComposite)comp; 396 rq.ensureCapacity(16); 397 buf.putInt(SET_ALPHA_COMPOSITE); 398 buf.putInt(ac.getRule()); 399 buf.putFloat(ac.getAlpha()); 400 buf.putInt(flags); 401 } else if (comp instanceof XORComposite) { 402 int xorPixel = ((XORComposite)comp).getXorPixel(); 403 rq.ensureCapacity(8); 404 buf.putInt(SET_XOR_COMPOSITE); 405 buf.putInt(xorPixel); 406 } else { 407 throw new InternalError("not yet implemented"); 408 } 409 } 410 411 private void resetTransform() { 412 // assert rq.lock.isHeldByCurrentThread(); 413 rq.ensureCapacity(4); 414 buf.putInt(RESET_TRANSFORM); 415 } 416 417 private void setTransform(AffineTransform xform) { 418 // assert rq.lock.isHeldByCurrentThread(); 419 rq.ensureCapacityAndAlignment(52, 4); 420 buf.putInt(SET_TRANSFORM); 421 buf.putDouble(xform.getScaleX()); 422 buf.putDouble(xform.getShearY()); 423 buf.putDouble(xform.getShearX()); 424 buf.putDouble(xform.getScaleY()); 425 buf.putDouble(xform.getTranslateX()); 426 buf.putDouble(xform.getTranslateY()); 427 } 428 429 /** 430 * Resets this context's surfaces and all attributes. 431 * 432 * Note: must be called while the RenderQueue lock is held. 433 * 434 * @see RenderQueue#lock 435 * @see RenderQueue#unlock 436 */ 437 public void invalidateContext() { 438 resetTransform(); 439 resetComposite(); 440 resetClip(); 441 BufferedPaints.resetPaint(rq); 442 invalidateSurfaces(); 443 validatedComp = null; 444 validatedClip = null; 445 validatedPaint = null; 446 isValidatedPaintJustAColor = false; 447 xformInUse = false; 448 } 449 450 /** 451 * Returns a singleton {@code RenderQueue} object used by the rendering 452 * pipeline. 453 * 454 * @return a render queue 455 * @see RenderQueue 456 */ 457 public abstract RenderQueue getRenderQueue(); 458 459 /** 460 * Saves the the state of this context. 461 * It may reset the current context. 462 * 463 * Note: must be called while the RenderQueue lock is held. 464 * 465 * @see RenderQueue#lock 466 * @see RenderQueue#unlock 467 */ 468 public abstract void saveState(); 469 470 /** 471 * Restores the native state of this context. 472 * It may reset the current context. 473 * 474 * Note: must be called while the RenderQueue lock is held. 475 * 476 * @see RenderQueue#lock 477 * @see RenderQueue#unlock 478 */ 479 public abstract void restoreState(); 480 }