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 }