1 /* 2 * Copyright (c) 2007, 2014, 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.d3d; 27 28 import java.awt.AlphaComposite; 29 import java.awt.BufferCapabilities; 30 import java.awt.Component; 31 import java.awt.GraphicsConfiguration; 32 import java.awt.GraphicsDevice; 33 import java.awt.GraphicsEnvironment; 34 import java.awt.Image; 35 import java.awt.Rectangle; 36 import java.awt.Transparency; 37 import java.awt.image.ColorModel; 38 import java.awt.image.DataBuffer; 39 import java.awt.image.DirectColorModel; 40 import java.awt.image.Raster; 41 import java.awt.image.SampleModel; 42 import java.awt.image.SinglePixelPackedSampleModel; 43 import sun.awt.SunHints; 44 import sun.awt.image.DataBufferNative; 45 import sun.awt.image.PixelConverter; 46 import sun.awt.image.SurfaceManager; 47 import sun.awt.image.WritableRasterNative; 48 import sun.awt.windows.WComponentPeer; 49 import sun.java2d.pipe.hw.AccelSurface; 50 import sun.java2d.InvalidPipeException; 51 import sun.java2d.SunGraphics2D; 52 import sun.java2d.SurfaceData; 53 import sun.java2d.loops.GraphicsPrimitive; 54 import sun.java2d.loops.MaskFill; 55 import sun.java2d.loops.SurfaceType; 56 import sun.java2d.loops.CompositeType; 57 import sun.java2d.pipe.ParallelogramPipe; 58 import sun.java2d.pipe.PixelToParallelogramConverter; 59 import sun.java2d.pipe.RenderBuffer; 60 import sun.java2d.pipe.TextPipe; 61 import static sun.java2d.pipe.BufferedOpCodes.*; 62 import static sun.java2d.d3d.D3DContext.D3DContextCaps.*; 63 import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*; 64 import sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType; 65 import java.awt.BufferCapabilities.FlipContents; 66 import java.awt.Dimension; 67 import java.awt.Window; 68 import java.awt.geom.AffineTransform; 69 import sun.awt.SunToolkit; 70 import sun.awt.image.SunVolatileImage; 71 import sun.awt.windows.WWindowPeer; 72 import sun.java2d.ScreenUpdateManager; 73 import sun.java2d.StateTracker; 74 import sun.java2d.SurfaceDataProxy; 75 import sun.java2d.pipe.hw.ExtendedBufferCapabilities; 76 77 /** 78 * This class describes a D3D "surface", that is, a region of pixels 79 * managed via D3D. An D3DSurfaceData can be tagged with one of three 80 * different SurfaceType objects for the purpose of registering loops, etc. 81 * This diagram shows the hierarchy of D3D SurfaceTypes: 82 * 83 * Any 84 * / \ 85 * D3DSurface D3DTexture 86 * | 87 * D3DSurfaceRTT 88 * 89 * D3DSurface 90 * This kind of surface can be rendered to using D3D APIs. It is also 91 * possible to copy a D3DSurface to another D3DSurface (or to itself). 92 * 93 * D3DTexture 94 * This kind of surface cannot be rendered to using D3D (in the same sense 95 * as in D3DSurface). However, it is possible to upload a region of pixels 96 * to a D3DTexture object via Lock/UnlockRect(). One can also copy a 97 * surface of type D3DTexture to a D3DSurface by binding the texture 98 * to a quad and then rendering it to the destination surface (this process 99 * is known as "texture mapping"). 100 * 101 * D3DSurfaceRTT 102 * This kind of surface can be thought of as a sort of hybrid between 103 * D3DSurface and D3DTexture, in that one can render to this kind of 104 * surface as if it were of type D3DSurface, but the process of copying 105 * this kind of surface to another is more like a D3DTexture. (Note that 106 * "RTT" stands for "render-to-texture".) 107 * 108 * In addition to these SurfaceType variants, we have also defined some 109 * constants that describe in more detail the type of underlying D3D 110 * surface. This table helps explain the relationships between those 111 * "type" constants and their corresponding SurfaceType: 112 * 113 * D3D Type Corresponding SurfaceType 114 * -------- ------------------------- 115 * RT_PLAIN D3DSurface 116 * TEXTURE D3DTexture 117 * FLIP_BACKBUFFER D3DSurface 118 * RT_TEXTURE D3DSurfaceRTT 119 */ 120 public class D3DSurfaceData extends SurfaceData implements AccelSurface { 121 122 /** 123 * To be used with getNativeResource() only. 124 * @see #getNativeResource 125 */ 126 public static final int D3D_DEVICE_RESOURCE= 100; 127 /* 128 * Surface types. 129 * We use these surface types when copying from a sw surface 130 * to a surface or texture. 131 */ 132 public static final int ST_INT_ARGB = 0; 133 public static final int ST_INT_ARGB_PRE = 1; 134 public static final int ST_INT_ARGB_BM = 2; 135 public static final int ST_INT_RGB = 3; 136 public static final int ST_INT_BGR = 4; 137 public static final int ST_USHORT_565_RGB = 5; 138 public static final int ST_USHORT_555_RGB = 6; 139 public static final int ST_BYTE_INDEXED = 7; 140 public static final int ST_BYTE_INDEXED_BM = 8; 141 public static final int ST_3BYTE_BGR = 9; 142 143 /** Equals to D3DSWAPEFFECT_DISCARD */ 144 public static final int SWAP_DISCARD = 1; 145 /** Equals to D3DSWAPEFFECT_FLIP */ 146 public static final int SWAP_FLIP = 2; 147 /** Equals to D3DSWAPEFFECT_COPY */ 148 public static final int SWAP_COPY = 3; 149 /* 150 * SurfaceTypes 151 */ 152 private static final String DESC_D3D_SURFACE = "D3D Surface"; 153 private static final String DESC_D3D_SURFACE_RTT = 154 "D3D Surface (render-to-texture)"; 155 private static final String DESC_D3D_TEXTURE = "D3D Texture"; 156 157 // REMIND: regarding ArgbPre?? 158 static final SurfaceType D3DSurface = 159 SurfaceType.Any.deriveSubType(DESC_D3D_SURFACE, 160 PixelConverter.ArgbPre.instance); 161 static final SurfaceType D3DSurfaceRTT = 162 D3DSurface.deriveSubType(DESC_D3D_SURFACE_RTT); 163 static final SurfaceType D3DTexture = 164 SurfaceType.Any.deriveSubType(DESC_D3D_TEXTURE); 165 166 private int type; 167 private int width, height; 168 private final double scaleX; 169 private final double scaleY; 170 // these fields are set from the native code when the surface is 171 // initialized 172 private int nativeWidth, nativeHeight; 173 protected WComponentPeer peer; 174 private Image offscreenImage; 175 protected D3DGraphicsDevice graphicsDevice; 176 177 private int swapEffect; 178 private VSyncType syncType; 179 private int backBuffersNum; 180 181 private WritableRasterNative wrn; 182 183 protected static D3DRenderer d3dRenderPipe; 184 protected static PixelToParallelogramConverter d3dTxRenderPipe; 185 protected static ParallelogramPipe d3dAAPgramPipe; 186 protected static D3DTextRenderer d3dTextPipe; 187 protected static D3DDrawImage d3dImagePipe; 188 189 private native boolean initTexture(long pData, boolean isRTT, 190 boolean isOpaque); 191 private native boolean initFlipBackbuffer(long pData, long pPeerData, 192 int numbuffers, 193 int swapEffect, int syncType); 194 private native boolean initRTSurface(long pData, boolean isOpaque); 195 private native void initOps(int screen, int width, int height); 196 197 static { 198 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 199 d3dImagePipe = new D3DDrawImage(); 200 d3dTextPipe = new D3DTextRenderer(rq); 201 d3dRenderPipe = new D3DRenderer(rq); 202 if (GraphicsPrimitive.tracingEnabled()) { 203 d3dTextPipe = d3dTextPipe.traceWrap(); 204 d3dRenderPipe = d3dRenderPipe.traceWrap(); 205 //The wrapped d3dRenderPipe will wrap the AA pipe as well... 206 //d3dAAPgramPipe = d3dRenderPipe.traceWrap(); 207 } 208 d3dAAPgramPipe = d3dRenderPipe.getAAParallelogramPipe(); 209 d3dTxRenderPipe = 210 new PixelToParallelogramConverter(d3dRenderPipe, d3dRenderPipe, 211 1.0, 0.25, true); 212 213 D3DBlitLoops.register(); 214 D3DMaskFill.register(); 215 D3DMaskBlit.register(); 216 } 217 218 protected D3DSurfaceData(WComponentPeer peer, D3DGraphicsConfig gc, 219 int width, int height, Image image, 220 ColorModel cm, int numBackBuffers, 221 int swapEffect, VSyncType vSyncType, 222 int type) 223 { 224 super(getCustomSurfaceType(type), cm); 225 this.graphicsDevice = gc.getD3DDevice(); 226 this.scaleX = type == TEXTURE ? 1 : graphicsDevice.getDefaultScaleX(); 227 this.scaleY = type == TEXTURE ? 1 : graphicsDevice.getDefaultScaleY(); 228 this.peer = peer; 229 this.type = type; 230 231 if (scaleX == 1 && scaleY == 1) { 232 this.width = width; 233 this.height = height; 234 } else if (peer instanceof WWindowPeer) { 235 Dimension scaledSize = ((WWindowPeer) peer).getScaledWindowSize(); 236 this.width = scaledSize.width; 237 this.height = scaledSize.height; 238 } else { 239 this.width = (int) Math.ceil(width * scaleX); 240 this.height = (int) Math.ceil(height * scaleY); 241 } 242 243 this.offscreenImage = image; 244 this.backBuffersNum = numBackBuffers; 245 this.swapEffect = swapEffect; 246 this.syncType = vSyncType; 247 248 initOps(graphicsDevice.getScreen(), this.width, this.height); 249 if (type == WINDOW) { 250 // we put the surface into the "lost" 251 // state; it will be restored by the D3DScreenUpdateManager 252 // prior to rendering to it for the first time. This is done 253 // so that vram is not wasted for surfaces never rendered to 254 setSurfaceLost(true); 255 } else { 256 initSurface(); 257 } 258 setBlitProxyKey(gc.getProxyKey()); 259 } 260 261 @Override 262 public double getDefaultScaleX() { 263 return scaleX; 264 } 265 266 @Override 267 public double getDefaultScaleY() { 268 return scaleY; 269 } 270 271 @Override 272 public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { 273 return D3DSurfaceDataProxy. 274 createProxy(srcData, 275 (D3DGraphicsConfig)graphicsDevice.getDefaultConfiguration()); 276 } 277 278 /** 279 * Creates a SurfaceData object representing the back buffer of a 280 * double-buffered on-screen Window. 281 */ 282 public static D3DSurfaceData createData(WComponentPeer peer, Image image) { 283 D3DGraphicsConfig gc = getGC(peer); 284 if (gc == null || !peer.isAccelCapable()) { 285 return null; 286 } 287 BufferCapabilities caps = peer.getBackBufferCaps(); 288 VSyncType vSyncType = VSYNC_DEFAULT; 289 if (caps instanceof ExtendedBufferCapabilities) { 290 vSyncType = ((ExtendedBufferCapabilities)caps).getVSync(); 291 } 292 Rectangle r = peer.getBounds(); 293 BufferCapabilities.FlipContents flip = caps.getFlipContents(); 294 int swapEffect; 295 if (flip == FlipContents.COPIED) { 296 swapEffect = SWAP_COPY; 297 } else if (flip == FlipContents.PRIOR) { 298 swapEffect = SWAP_FLIP; 299 } else { // flip == FlipContents.UNDEFINED || .BACKGROUND 300 swapEffect = SWAP_DISCARD; 301 } 302 return new D3DSurfaceData(peer, gc, r.width, r.height, 303 image, peer.getColorModel(), 304 peer.getBackBuffersNum(), 305 swapEffect, vSyncType, FLIP_BACKBUFFER); 306 } 307 308 /** 309 * Returns a WINDOW type of surface - a 310 * swap chain which serves as an on-screen surface, 311 * handled by the D3DScreenUpdateManager. 312 * 313 * Note that the native surface is not initialized 314 * when the surface is created to avoid using excessive 315 * resources, and the surface is placed into the lost 316 * state. It will be restored prior to any rendering 317 * to it. 318 * 319 * @param peer peer for which the onscreen surface is to be created 320 * @return a D3DWindowSurfaceData (flip chain) surface 321 */ 322 public static D3DSurfaceData createData(WComponentPeer peer) { 323 D3DGraphicsConfig gc = getGC(peer); 324 if (gc == null || !peer.isAccelCapable()) { 325 return null; 326 } 327 return new D3DWindowSurfaceData(peer, gc); 328 } 329 330 /** 331 * Creates a SurfaceData object representing an off-screen buffer (either 332 * a plain surface or Texture). 333 */ 334 public static D3DSurfaceData createData(D3DGraphicsConfig gc, 335 int width, int height, 336 ColorModel cm, 337 Image image, int type) 338 { 339 if (type == RT_TEXTURE) { 340 boolean isOpaque = cm.getTransparency() == Transparency.OPAQUE; 341 int cap = isOpaque ? CAPS_RT_TEXTURE_OPAQUE : CAPS_RT_TEXTURE_ALPHA; 342 if (!gc.getD3DDevice().isCapPresent(cap)) { 343 type = RT_PLAIN; 344 } 345 } 346 D3DSurfaceData ret = null; 347 try { 348 ret = new D3DSurfaceData(null, gc, width, height, 349 image, cm, 0, SWAP_DISCARD, VSYNC_DEFAULT, 350 type); 351 } catch (InvalidPipeException ipe) { 352 // try again - we might have ran out of vram, and rt textures 353 // could take up more than a plain surface, so it might succeed 354 if (type == RT_TEXTURE) { 355 // If a RT_TEXTURE was requested do not attempt to create a 356 // plain surface. (note that RT_TEXTURE can only be requested 357 // from a VI so the cast is safe) 358 if (((SunVolatileImage)image).getForcedAccelSurfaceType() != 359 RT_TEXTURE) 360 { 361 type = RT_PLAIN; 362 ret = new D3DSurfaceData(null, gc, width, height, 363 image, cm, 0, SWAP_DISCARD, 364 VSYNC_DEFAULT, type); 365 } 366 } 367 } 368 return ret; 369 } 370 371 /** 372 * Returns the appropriate SurfaceType corresponding to the given D3D 373 * surface type constant (e.g. TEXTURE -> D3DTexture). 374 */ 375 private static SurfaceType getCustomSurfaceType(int d3dType) { 376 switch (d3dType) { 377 case TEXTURE: 378 return D3DTexture; 379 case RT_TEXTURE: 380 return D3DSurfaceRTT; 381 default: 382 return D3DSurface; 383 } 384 } 385 386 private boolean initSurfaceNow() { 387 boolean isOpaque = (getTransparency() == Transparency.OPAQUE); 388 switch (type) { 389 case RT_PLAIN: 390 return initRTSurface(getNativeOps(), isOpaque); 391 case TEXTURE: 392 return initTexture(getNativeOps(), false/*isRTT*/, isOpaque); 393 case RT_TEXTURE: 394 return initTexture(getNativeOps(), true/*isRTT*/, isOpaque); 395 // REMIND: we may want to pass the exact type to the native 396 // level here so that we could choose the right presentation 397 // interval for the frontbuffer (immediate vs v-synced) 398 case WINDOW: 399 case FLIP_BACKBUFFER: 400 return initFlipBackbuffer(getNativeOps(), peer.getData(), 401 backBuffersNum, swapEffect, 402 syncType.id()); 403 default: 404 return false; 405 } 406 } 407 408 /** 409 * Initializes the appropriate D3D offscreen surface based on the value 410 * of the type parameter. If the surface creation fails for any reason, 411 * an OutOfMemoryError will be thrown. 412 */ 413 protected void initSurface() { 414 // any time we create or restore the surface, recreate the raster 415 synchronized (this) { 416 wrn = null; 417 } 418 // REMIND: somewhere a puppy died 419 class Status { 420 boolean success = false; 421 }; 422 final Status status = new Status(); 423 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 424 rq.lock(); 425 try { 426 rq.flushAndInvokeNow(new Runnable() { 427 public void run() { 428 status.success = initSurfaceNow(); 429 } 430 }); 431 if (!status.success) { 432 throw new InvalidPipeException("Error creating D3DSurface"); 433 } 434 } finally { 435 rq.unlock(); 436 } 437 } 438 439 /** 440 * Returns the D3DContext for the GraphicsConfig associated with this 441 * surface. 442 */ 443 public final D3DContext getContext() { 444 return graphicsDevice.getContext(); 445 } 446 447 /** 448 * Returns one of the surface type constants defined above. 449 */ 450 public final int getType() { 451 return type; 452 } 453 454 private static native int dbGetPixelNative(long pData, int x, int y); 455 private static native void dbSetPixelNative(long pData, int x, int y, 456 int pixel); 457 static class D3DDataBufferNative extends DataBufferNative { 458 int pixel; 459 protected D3DDataBufferNative(SurfaceData sData, 460 int type, int w, int h) 461 { 462 super(sData, type, w, h); 463 } 464 465 protected int getElem(final int x, final int y, 466 final SurfaceData sData) 467 { 468 if (sData.isSurfaceLost()) { 469 return 0; 470 } 471 472 int retPixel; 473 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 474 rq.lock(); 475 try { 476 rq.flushAndInvokeNow(new Runnable() { 477 public void run() { 478 pixel = dbGetPixelNative(sData.getNativeOps(), x, y); 479 } 480 }); 481 } finally { 482 retPixel = pixel; 483 rq.unlock(); 484 } 485 return retPixel; 486 } 487 488 protected void setElem(final int x, final int y, final int pixel, 489 final SurfaceData sData) 490 { 491 if (sData.isSurfaceLost()) { 492 return; 493 } 494 495 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 496 rq.lock(); 497 try { 498 rq.flushAndInvokeNow(new Runnable() { 499 public void run() { 500 dbSetPixelNative(sData.getNativeOps(), x, y, pixel); 501 } 502 }); 503 sData.markDirty(); 504 } finally { 505 rq.unlock(); 506 } 507 } 508 } 509 510 public synchronized Raster getRaster(int x, int y, int w, int h) { 511 if (wrn == null) { 512 DirectColorModel dcm = (DirectColorModel)getColorModel(); 513 SampleModel smHw; 514 int dataType = 0; 515 int scanStride = width; 516 517 if (dcm.getPixelSize() > 16) { 518 dataType = DataBuffer.TYPE_INT; 519 } else { 520 // 15, 16 521 dataType = DataBuffer.TYPE_USHORT; 522 } 523 524 // note that we have to use the surface width and height here, 525 // not the passed w,h 526 smHw = new SinglePixelPackedSampleModel(dataType, width, height, 527 scanStride, dcm.getMasks()); 528 DataBuffer dbn = new D3DDataBufferNative(this, dataType, 529 width, height); 530 wrn = WritableRasterNative.createNativeRaster(smHw, dbn); 531 } 532 533 return wrn; 534 } 535 536 /** 537 * For now, we can only render LCD text if: 538 * - the pixel shaders are available, and 539 * - blending is disabled, and 540 * - the source color is opaque 541 * - and the destination is opaque 542 */ 543 public boolean canRenderLCDText(SunGraphics2D sg2d) { 544 return 545 graphicsDevice.isCapPresent(CAPS_LCD_SHADER) && 546 sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && 547 sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR && 548 sg2d.surfaceData.getTransparency() == Transparency.OPAQUE; 549 } 550 551 /** 552 * If acceleration should no longer be used for this surface. 553 * This implementation flags to the manager that it should no 554 * longer attempt to re-create a D3DSurface. 555 */ 556 void disableAccelerationForSurface() { 557 if (offscreenImage != null) { 558 SurfaceManager sm = SurfaceManager.getManager(offscreenImage); 559 if (sm instanceof D3DVolatileSurfaceManager) { 560 setSurfaceLost(true); 561 ((D3DVolatileSurfaceManager)sm).setAccelerationEnabled(false); 562 } 563 } 564 } 565 566 public void validatePipe(SunGraphics2D sg2d) { 567 TextPipe textpipe; 568 boolean validated = false; 569 570 // REMIND: the D3D pipeline doesn't support XOR!, more 571 // fixes will be needed below. For now we disable D3D rendering 572 // for the surface which had any XOR rendering done to. 573 if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) { 574 super.validatePipe(sg2d); 575 sg2d.imagepipe = d3dImagePipe; 576 disableAccelerationForSurface(); 577 return; 578 } 579 580 // D3DTextRenderer handles both AA and non-AA text, but 581 // only works with the following modes: 582 // (Note: For LCD text we only enter this code path if 583 // canRenderLCDText() has already validated that the mode is 584 // CompositeType.SrcNoEa (opaque color), which will be subsumed 585 // by the CompositeType.SrcNoEa (any color) test below.) 586 587 if (/* CompositeType.SrcNoEa (any color) */ 588 (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && 589 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) || 590 591 /* CompositeType.SrcOver (any color) */ 592 (sg2d.compositeState == SunGraphics2D.COMP_ALPHA && 593 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && 594 (((AlphaComposite)sg2d.composite).getRule() == 595 AlphaComposite.SRC_OVER)) || 596 597 /* CompositeType.Xor (any color) */ 598 (sg2d.compositeState == SunGraphics2D.COMP_XOR && 599 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR)) 600 { 601 textpipe = d3dTextPipe; 602 } else { 603 // do this to initialize textpipe correctly; we will attempt 604 // to override the non-text pipes below 605 super.validatePipe(sg2d); 606 textpipe = sg2d.textpipe; 607 validated = true; 608 } 609 610 PixelToParallelogramConverter txPipe = null; 611 D3DRenderer nonTxPipe = null; 612 613 if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { 614 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { 615 if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) { 616 txPipe = d3dTxRenderPipe; 617 nonTxPipe = d3dRenderPipe; 618 } 619 } else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) { 620 if (D3DPaints.isValid(sg2d)) { 621 txPipe = d3dTxRenderPipe; 622 nonTxPipe = d3dRenderPipe; 623 } 624 // custom paints handled by super.validatePipe() below 625 } 626 } else { 627 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { 628 if (graphicsDevice.isCapPresent(CAPS_AA_SHADER) && 629 (sg2d.imageComp == CompositeType.SrcOverNoEa || 630 sg2d.imageComp == CompositeType.SrcOver)) 631 { 632 if (!validated) { 633 super.validatePipe(sg2d); 634 validated = true; 635 } 636 PixelToParallelogramConverter aaConverter = 637 new PixelToParallelogramConverter(sg2d.shapepipe, 638 d3dAAPgramPipe, 639 1.0/8.0, 0.499, 640 false); 641 sg2d.drawpipe = aaConverter; 642 sg2d.fillpipe = aaConverter; 643 sg2d.shapepipe = aaConverter; 644 } else if (sg2d.compositeState == SunGraphics2D.COMP_XOR) { 645 // install the solid pipes when AA and XOR are both enabled 646 txPipe = d3dTxRenderPipe; 647 nonTxPipe = d3dRenderPipe; 648 } 649 } 650 // other cases handled by super.validatePipe() below 651 } 652 653 if (txPipe != null) { 654 if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { 655 sg2d.drawpipe = txPipe; 656 sg2d.fillpipe = txPipe; 657 } else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) { 658 sg2d.drawpipe = txPipe; 659 sg2d.fillpipe = nonTxPipe; 660 } else { 661 sg2d.drawpipe = nonTxPipe; 662 sg2d.fillpipe = nonTxPipe; 663 } 664 // Note that we use the transforming pipe here because it 665 // will examine the shape and possibly perform an optimized 666 // operation if it can be simplified. The simplifications 667 // will be valid for all STROKE and TRANSFORM types. 668 sg2d.shapepipe = txPipe; 669 } else { 670 if (!validated) { 671 super.validatePipe(sg2d); 672 } 673 } 674 675 // install the text pipe based on our earlier decision 676 sg2d.textpipe = textpipe; 677 678 // always override the image pipe with the specialized D3D pipe 679 sg2d.imagepipe = d3dImagePipe; 680 } 681 682 @Override 683 protected MaskFill getMaskFill(SunGraphics2D sg2d) { 684 if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) { 685 /* 686 * We can only accelerate non-Color MaskFill operations if 687 * all of the following conditions hold true: 688 * - there is an implementation for the given paintState 689 * - the current Paint can be accelerated for this destination 690 * - multitexturing is available (since we need to modulate 691 * the alpha mask texture with the paint texture) 692 * 693 * In all other cases, we return null, in which case the 694 * validation code will choose a more general software-based loop. 695 */ 696 if (!D3DPaints.isValid(sg2d) || 697 !graphicsDevice.isCapPresent(CAPS_MULTITEXTURE)) 698 { 699 return null; 700 } 701 } 702 return super.getMaskFill(sg2d); 703 } 704 705 @Override 706 public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, 707 int dx, int dy) { 708 if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) { 709 return false; 710 } 711 d3dRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); 712 return true; 713 } 714 715 @Override 716 public void flush() { 717 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 718 rq.lock(); 719 try { 720 RenderBuffer buf = rq.getBuffer(); 721 rq.ensureCapacityAndAlignment(12, 4); 722 buf.putInt(FLUSH_SURFACE); 723 buf.putLong(getNativeOps()); 724 725 // this call is expected to complete synchronously, so flush now 726 rq.flushNow(); 727 } finally { 728 rq.unlock(); 729 } 730 } 731 732 /** 733 * Disposes the native resources associated with the given D3DSurfaceData 734 * (referenced by the pData parameter). This method is invoked from 735 * the native Dispose() method from the Disposer thread when the 736 * Java-level D3DSurfaceData object is about to go away. 737 */ 738 static void dispose(long pData) { 739 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 740 rq.lock(); 741 try { 742 RenderBuffer buf = rq.getBuffer(); 743 rq.ensureCapacityAndAlignment(12, 4); 744 buf.putInt(DISPOSE_SURFACE); 745 buf.putLong(pData); 746 747 // this call is expected to complete synchronously, so flush now 748 rq.flushNow(); 749 } finally { 750 rq.unlock(); 751 } 752 } 753 754 static void swapBuffers(D3DSurfaceData sd, 755 final int x1, final int y1, 756 final int x2, final int y2) 757 { 758 long pData = sd.getNativeOps(); 759 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 760 // swapBuffers can be called from the toolkit thread by swing, we 761 // should detect this and prevent the deadlocks 762 if (D3DRenderQueue.isRenderQueueThread()) { 763 if (!rq.tryLock()) { 764 // if we could not obtain the lock, repaint the area 765 // that was supposed to be swapped, and no-op this swap 766 final Component target = (Component)sd.getPeer().getTarget(); 767 SunToolkit.executeOnEventHandlerThread(target, new Runnable() { 768 public void run() { 769 double scaleX = sd.getDefaultScaleX(); 770 double scaleY = sd.getDefaultScaleY(); 771 if (scaleX > 1 || scaleY > 1) { 772 int sx1 = (int) Math.floor(x1 / scaleX); 773 int sy1 = (int) Math.floor(y1 / scaleY); 774 int sx2 = (int) Math.ceil(x2 / scaleX); 775 int sy2 = (int) Math.ceil(y2 / scaleY); 776 target.repaint(sx1, sy1, sx2 - sx1, sy2 - sy1); 777 } else { 778 target.repaint(x1, y1, x2 - x1, y2 - y1); 779 } 780 } 781 }); 782 return; 783 } 784 } else { 785 rq.lock(); 786 } 787 try { 788 RenderBuffer buf = rq.getBuffer(); 789 rq.ensureCapacityAndAlignment(28, 4); 790 buf.putInt(SWAP_BUFFERS); 791 buf.putLong(pData); 792 buf.putInt(x1); 793 buf.putInt(y1); 794 buf.putInt(x2); 795 buf.putInt(y2); 796 rq.flushNow(); 797 } finally { 798 rq.unlock(); 799 } 800 } 801 802 /** 803 * Returns destination Image associated with this SurfaceData. 804 */ 805 public Object getDestination() { 806 return offscreenImage; 807 } 808 809 public Rectangle getBounds() { 810 if (type == FLIP_BACKBUFFER || type == WINDOW) { 811 double scaleX = getDefaultScaleX(); 812 double scaleY = getDefaultScaleY(); 813 Rectangle r = peer.getBounds(); 814 r.x = r.y = 0; 815 r.width = (int) Math.ceil(r.width * scaleX); 816 r.height = (int) Math.ceil(r.height * scaleY); 817 return r; 818 } else { 819 return new Rectangle(width, height); 820 } 821 } 822 823 public Rectangle getNativeBounds() { 824 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 825 // need to lock to make sure nativeWidth and Height are consistent 826 // since they are set from the render thread from the native 827 // level 828 rq.lock(); 829 try { 830 // REMIND: use xyoffsets? 831 return new Rectangle(nativeWidth, nativeHeight); 832 } finally { 833 rq.unlock(); 834 } 835 } 836 837 838 public GraphicsConfiguration getDeviceConfiguration() { 839 return graphicsDevice.getDefaultConfiguration(); 840 } 841 842 public SurfaceData getReplacement() { 843 return restoreContents(offscreenImage); 844 } 845 846 private static D3DGraphicsConfig getGC(WComponentPeer peer) { 847 GraphicsConfiguration gc; 848 if (peer != null) { 849 gc = peer.getGraphicsConfiguration(); 850 } else { 851 GraphicsEnvironment env = 852 GraphicsEnvironment.getLocalGraphicsEnvironment(); 853 GraphicsDevice gd = env.getDefaultScreenDevice(); 854 gc = gd.getDefaultConfiguration(); 855 } 856 return (gc instanceof D3DGraphicsConfig) ? (D3DGraphicsConfig)gc : null; 857 } 858 859 /** 860 * Attempts to restore the surface by initializing the native data 861 */ 862 void restoreSurface() { 863 initSurface(); 864 } 865 866 WComponentPeer getPeer() { 867 return peer; 868 } 869 870 /** 871 * We need to let the surface manager know that the surface is lost so 872 * that for example BufferStrategy.contentsLost() returns correct result. 873 * Normally the status of contentsLost is set in validate(), but in some 874 * cases (like Swing's buffer per window) we intentionally don't call 875 * validate from the toolkit thread but only check for the BS status. 876 */ 877 @Override 878 public void setSurfaceLost(boolean lost) { 879 super.setSurfaceLost(lost); 880 if (lost && offscreenImage != null) { 881 SurfaceManager sm = SurfaceManager.getManager(offscreenImage); 882 sm.acceleratedSurfaceLost(); 883 } 884 } 885 886 private static native long getNativeResourceNative(long sdops, int resType); 887 /** 888 * Returns a pointer to the native resource of specified {@code resType} 889 * associated with this surface. 890 * 891 * Specifically, for {@code D3DSurfaceData} this method returns pointers of 892 * the following: 893 * <pre> 894 * TEXTURE - (IDirect3DTexture9*) 895 * RT_TEXTURE, RT_PLAIN - (IDirect3DSurface9*) 896 * FLIP_BACKBUFFER - (IDirect3DSwapChain9*) 897 * D3D_DEVICE_RESOURCE - (IDirect3DDevice9*) 898 * </pre> 899 * 900 * Multiple resources may be available for some types (i.e. for render to 901 * texture one could retrieve both a destination surface by specifying 902 * RT_TEXTURE, and a texture by using TEXTURE). 903 * 904 * Note: the pointer returned by this method is only valid on the rendering 905 * thread. 906 * 907 * @return pointer to the native resource of specified type or 0L if 908 * such resource doesn't exist or can not be retrieved. 909 * @see sun.java2d.pipe.hw.AccelSurface#getNativeResource 910 */ 911 public long getNativeResource(int resType) { 912 return getNativeResourceNative(getNativeOps(), resType); 913 } 914 915 /** 916 * Class representing an on-screen d3d surface. Since d3d can't 917 * render to the screen directly, it is implemented as a swap chain, 918 * controlled by D3DScreenUpdateManager. 919 * 920 * @see D3DScreenUpdateManager 921 */ 922 public static class D3DWindowSurfaceData extends D3DSurfaceData { 923 StateTracker dirtyTracker; 924 925 public D3DWindowSurfaceData(WComponentPeer peer, 926 D3DGraphicsConfig gc) 927 { 928 super(peer, gc, 929 peer.getBounds().width, peer.getBounds().height, 930 null, peer.getColorModel(), 1, SWAP_COPY, VSYNC_DEFAULT, 931 WINDOW); 932 dirtyTracker = getStateTracker(); 933 } 934 935 /** 936 * {@inheritDoc} 937 * 938 * Overridden to use ScreenUpdateManager to obtain the replacement 939 * surface. 940 * 941 * @see sun.java2d.ScreenUpdateManager#getReplacementScreenSurface 942 */ 943 @Override 944 public SurfaceData getReplacement() { 945 ScreenUpdateManager mgr = ScreenUpdateManager.getInstance(); 946 return mgr.getReplacementScreenSurface(peer, this); 947 } 948 949 /** 950 * Returns destination Component associated with this SurfaceData. 951 */ 952 @Override 953 public Object getDestination() { 954 return peer.getTarget(); 955 } 956 957 @Override 958 void disableAccelerationForSurface() { 959 // for on-screen surfaces we need to make sure a backup GDI surface is 960 // is used until a new one is set (which may happen during a resize). We 961 // don't want the screen update maanger to replace the surface right way 962 // because it causes repainting issues in Swing, so we invalidate it, 963 // this will prevent SUM from issuing a replaceSurfaceData call. 964 setSurfaceLost(true); 965 invalidate(); 966 flush(); 967 peer.disableAcceleration(); 968 ScreenUpdateManager.getInstance().dropScreenSurface(this); 969 } 970 971 @Override 972 void restoreSurface() { 973 if (!peer.isAccelCapable()) { 974 throw new InvalidPipeException("Onscreen acceleration " + 975 "disabled for this surface"); 976 } 977 Window fsw = graphicsDevice.getFullScreenWindow(); 978 if (fsw != null && fsw != peer.getTarget()) { 979 throw new InvalidPipeException("Can't restore onscreen surface"+ 980 " when in full-screen mode"); 981 } 982 super.restoreSurface(); 983 // if initialization was unsuccessful, an IPE will be thrown 984 // and the surface will remain lost 985 setSurfaceLost(false); 986 987 // This is to make sure the render target is reset after this 988 // surface is restored. The reason for this is that sometimes this 989 // surface can be restored from multiple threads (the screen update 990 // manager's thread and app's rendering thread) at the same time, 991 // and when that happens the second restoration will create the 992 // native resource which will not be set as render target because 993 // the BufferedContext's validate method will think that since the 994 // surface data object didn't change then the current render target 995 // is correct and no rendering will appear on the screen. 996 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 997 rq.lock(); 998 try { 999 getContext().invalidateContext(); 1000 } finally { 1001 rq.unlock(); 1002 } 1003 } 1004 1005 public boolean isDirty() { 1006 return !dirtyTracker.isCurrent(); 1007 } 1008 1009 public void markClean() { 1010 dirtyTracker = getStateTracker(); 1011 } 1012 } 1013 1014 /** 1015 * Updates the layered window with the contents of the surface. 1016 * 1017 * @param pd3dsd pointer to the D3DSDOps structure 1018 * @param pData pointer to the AwtWindow peer data 1019 * @param w width of the window 1020 * @param h height of the window 1021 * @see sun.awt.windows.TranslucentWindowPainter 1022 */ 1023 public static native boolean updateWindowAccelImpl(long pd3dsd, long pData, 1024 int w, int h); 1025 }