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