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