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 final int state = sg2d.transformState; 709 if (state > SunGraphics2D.TRANSFORM_TRANSLATESCALE 710 || sg2d.compositeState >= SunGraphics2D.COMP_XOR) { 711 return false; 712 } 713 d3dRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); 714 return true; 715 } 716 717 @Override 718 public void flush() { 719 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 720 rq.lock(); 721 try { 722 RenderBuffer buf = rq.getBuffer(); 723 rq.ensureCapacityAndAlignment(12, 4); 724 buf.putInt(FLUSH_SURFACE); 725 buf.putLong(getNativeOps()); 726 727 // this call is expected to complete synchronously, so flush now 728 rq.flushNow(); 729 } finally { 730 rq.unlock(); 731 } 732 } 733 734 /** 735 * Disposes the native resources associated with the given D3DSurfaceData 736 * (referenced by the pData parameter). This method is invoked from 737 * the native Dispose() method from the Disposer thread when the 738 * Java-level D3DSurfaceData object is about to go away. 739 */ 740 static void dispose(long pData) { 741 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 742 rq.lock(); 743 try { 744 RenderBuffer buf = rq.getBuffer(); 745 rq.ensureCapacityAndAlignment(12, 4); 746 buf.putInt(DISPOSE_SURFACE); 747 buf.putLong(pData); 748 749 // this call is expected to complete synchronously, so flush now 750 rq.flushNow(); 751 } finally { 752 rq.unlock(); 753 } 754 } 755 756 static void swapBuffers(D3DSurfaceData sd, 757 final int x1, final int y1, 758 final int x2, final int y2) 759 { 760 long pData = sd.getNativeOps(); 761 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 762 // swapBuffers can be called from the toolkit thread by swing, we 763 // should detect this and prevent the deadlocks 764 if (D3DRenderQueue.isRenderQueueThread()) { 765 if (!rq.tryLock()) { 766 // if we could not obtain the lock, repaint the area 767 // that was supposed to be swapped, and no-op this swap 768 final Component target = (Component)sd.getPeer().getTarget(); 769 SunToolkit.executeOnEventHandlerThread(target, new Runnable() { 770 public void run() { 771 target.repaint(x1, y1, x2, y2); 772 } 773 }); 774 return; 775 } 776 } else { 777 rq.lock(); 778 } 779 try { 780 RenderBuffer buf = rq.getBuffer(); 781 rq.ensureCapacityAndAlignment(28, 4); 782 buf.putInt(SWAP_BUFFERS); 783 buf.putLong(pData); 784 buf.putInt(x1); 785 buf.putInt(y1); 786 buf.putInt(x2); 787 buf.putInt(y2); 788 rq.flushNow(); 789 } finally { 790 rq.unlock(); 791 } 792 } 793 794 /** 795 * Returns destination Image associated with this SurfaceData. 796 */ 797 public Object getDestination() { 798 return offscreenImage; 799 } 800 801 public Rectangle getBounds() { 802 if (type == FLIP_BACKBUFFER || type == WINDOW) { 803 double scaleX = getDefaultScaleX(); 804 double scaleY = getDefaultScaleY(); 805 Rectangle r = peer.getBounds(); 806 r.x = r.y = 0; 807 r.width = (int) Math.ceil(r.width * scaleX); 808 r.height = (int) Math.ceil(r.height * scaleY); 809 return r; 810 } else { 811 return new Rectangle(width, height); 812 } 813 } 814 815 public Rectangle getNativeBounds() { 816 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 817 // need to lock to make sure nativeWidth and Height are consistent 818 // since they are set from the render thread from the native 819 // level 820 rq.lock(); 821 try { 822 // REMIND: use xyoffsets? 823 return new Rectangle(nativeWidth, nativeHeight); 824 } finally { 825 rq.unlock(); 826 } 827 } 828 829 830 public GraphicsConfiguration getDeviceConfiguration() { 831 return graphicsDevice.getDefaultConfiguration(); 832 } 833 834 public SurfaceData getReplacement() { 835 return restoreContents(offscreenImage); 836 } 837 838 private static D3DGraphicsConfig getGC(WComponentPeer peer) { 839 GraphicsConfiguration gc; 840 if (peer != null) { 841 gc = peer.getGraphicsConfiguration(); 842 } else { 843 GraphicsEnvironment env = 844 GraphicsEnvironment.getLocalGraphicsEnvironment(); 845 GraphicsDevice gd = env.getDefaultScreenDevice(); 846 gc = gd.getDefaultConfiguration(); 847 } 848 return (gc instanceof D3DGraphicsConfig) ? (D3DGraphicsConfig)gc : null; 849 } 850 851 /** 852 * Attempts to restore the surface by initializing the native data 853 */ 854 void restoreSurface() { 855 initSurface(); 856 } 857 858 WComponentPeer getPeer() { 859 return peer; 860 } 861 862 /** 863 * We need to let the surface manager know that the surface is lost so 864 * that for example BufferStrategy.contentsLost() returns correct result. 865 * Normally the status of contentsLost is set in validate(), but in some 866 * cases (like Swing's buffer per window) we intentionally don't call 867 * validate from the toolkit thread but only check for the BS status. 868 */ 869 @Override 870 public void setSurfaceLost(boolean lost) { 871 super.setSurfaceLost(lost); 872 if (lost && offscreenImage != null) { 873 SurfaceManager sm = SurfaceManager.getManager(offscreenImage); 874 sm.acceleratedSurfaceLost(); 875 } 876 } 877 878 private static native long getNativeResourceNative(long sdops, int resType); 879 /** 880 * Returns a pointer to the native resource of specified {@code resType} 881 * associated with this surface. 882 * 883 * Specifically, for {@code D3DSurfaceData} this method returns pointers of 884 * the following: 885 * <pre> 886 * TEXTURE - (IDirect3DTexture9*) 887 * RT_TEXTURE, RT_PLAIN - (IDirect3DSurface9*) 888 * FLIP_BACKBUFFER - (IDirect3DSwapChain9*) 889 * D3D_DEVICE_RESOURCE - (IDirect3DDevice9*) 890 * </pre> 891 * 892 * Multiple resources may be available for some types (i.e. for render to 893 * texture one could retrieve both a destination surface by specifying 894 * RT_TEXTURE, and a texture by using TEXTURE). 895 * 896 * Note: the pointer returned by this method is only valid on the rendering 897 * thread. 898 * 899 * @return pointer to the native resource of specified type or 0L if 900 * such resource doesn't exist or can not be retrieved. 901 * @see sun.java2d.pipe.hw.AccelSurface#getNativeResource 902 */ 903 public long getNativeResource(int resType) { 904 return getNativeResourceNative(getNativeOps(), resType); 905 } 906 907 /** 908 * Class representing an on-screen d3d surface. Since d3d can't 909 * render to the screen directly, it is implemented as a swap chain, 910 * controlled by D3DScreenUpdateManager. 911 * 912 * @see D3DScreenUpdateManager 913 */ 914 public static class D3DWindowSurfaceData extends D3DSurfaceData { 915 StateTracker dirtyTracker; 916 917 public D3DWindowSurfaceData(WComponentPeer peer, 918 D3DGraphicsConfig gc) 919 { 920 super(peer, gc, 921 peer.getBounds().width, peer.getBounds().height, 922 null, peer.getColorModel(), 1, SWAP_COPY, VSYNC_DEFAULT, 923 WINDOW); 924 dirtyTracker = getStateTracker(); 925 } 926 927 /** 928 * {@inheritDoc} 929 * 930 * Overridden to use ScreenUpdateManager to obtain the replacement 931 * surface. 932 * 933 * @see sun.java2d.ScreenUpdateManager#getReplacementScreenSurface 934 */ 935 @Override 936 public SurfaceData getReplacement() { 937 ScreenUpdateManager mgr = ScreenUpdateManager.getInstance(); 938 return mgr.getReplacementScreenSurface(peer, this); 939 } 940 941 /** 942 * Returns destination Component associated with this SurfaceData. 943 */ 944 @Override 945 public Object getDestination() { 946 return peer.getTarget(); 947 } 948 949 @Override 950 void disableAccelerationForSurface() { 951 // for on-screen surfaces we need to make sure a backup GDI surface is 952 // is used until a new one is set (which may happen during a resize). We 953 // don't want the screen update maanger to replace the surface right way 954 // because it causes repainting issues in Swing, so we invalidate it, 955 // this will prevent SUM from issuing a replaceSurfaceData call. 956 setSurfaceLost(true); 957 invalidate(); 958 flush(); 959 peer.disableAcceleration(); 960 ScreenUpdateManager.getInstance().dropScreenSurface(this); 961 } 962 963 @Override 964 void restoreSurface() { 965 if (!peer.isAccelCapable()) { 966 throw new InvalidPipeException("Onscreen acceleration " + 967 "disabled for this surface"); 968 } 969 Window fsw = graphicsDevice.getFullScreenWindow(); 970 if (fsw != null && fsw != peer.getTarget()) { 971 throw new InvalidPipeException("Can't restore onscreen surface"+ 972 " when in full-screen mode"); 973 } 974 super.restoreSurface(); 975 // if initialization was unsuccessful, an IPE will be thrown 976 // and the surface will remain lost 977 setSurfaceLost(false); 978 979 // This is to make sure the render target is reset after this 980 // surface is restored. The reason for this is that sometimes this 981 // surface can be restored from multiple threads (the screen update 982 // manager's thread and app's rendering thread) at the same time, 983 // and when that happens the second restoration will create the 984 // native resource which will not be set as render target because 985 // the BufferedContext's validate method will think that since the 986 // surface data object didn't change then the current render target 987 // is correct and no rendering will appear on the screen. 988 D3DRenderQueue rq = D3DRenderQueue.getInstance(); 989 rq.lock(); 990 try { 991 getContext().invalidateContext(); 992 } finally { 993 rq.unlock(); 994 } 995 } 996 997 public boolean isDirty() { 998 return !dirtyTracker.isCurrent(); 999 } 1000 1001 public void markClean() { 1002 dirtyTracker = getStateTracker(); 1003 } 1004 } 1005 1006 /** 1007 * Updates the layered window with the contents of the surface. 1008 * 1009 * @param pd3dsd pointer to the D3DSDOps structure 1010 * @param pData pointer to the AwtWindow peer data 1011 * @param w width of the window 1012 * @param h height of the window 1013 * @see sun.awt.windows.TranslucentWindowPainter 1014 */ 1015 public static native boolean updateWindowAccelImpl(long pd3dsd, long pData, 1016 int w, int h); 1017 }