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