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