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