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 initTexture(long pData, boolean isRTT, boolean isOpaque)190 private native boolean initTexture(long pData, boolean isRTT, 191 boolean isOpaque); initFlipBackbuffer(long pData, long pPeerData, int numbuffers, int swapEffect, int syncType)192 private native boolean initFlipBackbuffer(long pData, long pPeerData, 193 int numbuffers, 194 int swapEffect, int syncType); initRTSurface(long pData, boolean isOpaque)195 private native boolean initRTSurface(long pData, boolean isOpaque); initOps(int screen, int width, int height)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 D3DBlitLoops.register()214 D3DBlitLoops.register(); D3DMaskFill.register()215 D3DMaskFill.register(); D3DMaskBlit.register()216 D3DMaskBlit.register(); 217 } 218 D3DSurfaceData(WComponentPeer peer, D3DGraphicsConfig gc, int width, int height, Image image, ColorModel cm, int numBackBuffers, int swapEffect, VSyncType vSyncType, int type)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 getDefaultScaleX()263 public double getDefaultScaleX() { 264 return scaleX; 265 } 266 267 @Override getDefaultScaleY()268 public double getDefaultScaleY() { 269 return scaleY; 270 } 271 272 @Override makeProxyFor(SurfaceData srcData)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 */ createData(WComponentPeer peer, Image image)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 */ createData(WComponentPeer peer)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 */ createData(D3DGraphicsConfig gc, int width, int height, ColorModel cm, Image image, int type)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 */ getCustomSurfaceType(int d3dType)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 initSurfaceNow()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 */ initSurface()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 */ getContext()444 public final D3DContext getContext() { 445 return graphicsDevice.getContext(); 446 } 447 448 /** 449 * Returns one of the surface type constants defined above. 450 */ getType()451 public final int getType() { 452 return type; 453 } 454 dbGetPixelNative(long pData, int x, int y)455 private static native int dbGetPixelNative(long pData, int x, int y); dbSetPixelNative(long pData, int x, int y, int pixel)456 private static native void dbSetPixelNative(long pData, int x, int y, 457 int pixel); 458 static class D3DDataBufferNative extends DataBufferNative { 459 int pixel; D3DDataBufferNative(SurfaceData sData, int type, int w, int h)460 protected D3DDataBufferNative(SurfaceData sData, 461 int type, int w, int h) 462 { 463 super(sData, type, w, h); 464 } 465 getElem(final int x, final int y, final SurfaceData sData)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 setElem(final int x, final int y, final int pixel, final SurfaceData sData)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 getRaster(int x, int y, int w, int h)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 */ canRenderLCDText(SunGraphics2D sg2d)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 */ disableAccelerationForSurface()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 validatePipe(SunGraphics2D sg2d)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 getMaskFill(SunGraphics2D sg2d)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 copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy)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 flush()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 */ dispose(long pData)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 swapBuffers(D3DSurfaceData sd, final int x1, final int y1, final int x2, final int y2)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 */ getDestination()806 public Object getDestination() { 807 return offscreenImage; 808 } 809 getBounds()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 getNativeBounds()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 getDeviceConfiguration()839 public GraphicsConfiguration getDeviceConfiguration() { 840 return graphicsDevice.getDefaultConfiguration(); 841 } 842 getReplacement()843 public SurfaceData getReplacement() { 844 return restoreContents(offscreenImage); 845 } 846 getGC(WComponentPeer peer)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 */ restoreSurface()863 void restoreSurface() { 864 initSurface(); 865 } 866 getPeer()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 setSurfaceLost(boolean lost)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 getNativeResourceNative(long sdops, int resType)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 */ getNativeResource(int resType)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 D3DWindowSurfaceData(WComponentPeer peer, D3DGraphicsConfig gc)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 getReplacement()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 getDestination()954 public Object getDestination() { 955 return peer.getTarget(); 956 } 957 958 @Override disableAccelerationForSurface()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 restoreSurface()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 isDirty()1006 public boolean isDirty() { 1007 return !dirtyTracker.isCurrent(); 1008 } 1009 markClean()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 */ updateWindowAccelImpl(long pd3dsd, long pData, int w, int h)1024 public static native boolean updateWindowAccelImpl(long pd3dsd, long pData, 1025 int w, int h); 1026 } 1027