aboutsummaryrefslogtreecommitdiff
path: root/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
blob: 3d1457c721f0005fd849876ee659d287c98815b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
/*
 * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package sun.java2d.d3d;

import java.awt.AlphaComposite;
import java.awt.BufferCapabilities;
import java.awt.Component;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import sun.awt.SunHints;
import sun.awt.image.DataBufferNative;
import sun.awt.image.PixelConverter;
import sun.awt.image.SurfaceManager;
import sun.awt.image.WritableRasterNative;
import sun.awt.windows.WComponentPeer;
import sun.java2d.pipe.hw.AccelSurface;
import sun.java2d.InvalidPipeException;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.loops.MaskFill;
import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.CompositeType;
import sun.java2d.pipe.ParallelogramPipe;
import sun.java2d.pipe.PixelToParallelogramConverter;
import sun.java2d.pipe.RenderBuffer;
import sun.java2d.pipe.TextPipe;
import static sun.java2d.pipe.BufferedOpCodes.*;
import static sun.java2d.d3d.D3DContext.D3DContextCaps.*;
import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*;
import sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType;
import java.awt.BufferCapabilities.FlipContents;
import java.awt.Window;
import sun.awt.SunToolkit;
import sun.awt.image.SunVolatileImage;
import sun.java2d.ScreenUpdateManager;
import sun.java2d.StateTracker;
import sun.java2d.SurfaceDataProxy;
import sun.java2d.pipe.hw.ExtendedBufferCapabilities;

/**
 * This class describes a D3D "surface", that is, a region of pixels
 * managed via D3D.  An D3DSurfaceData can be tagged with one of three
 * different SurfaceType objects for the purpose of registering loops, etc.
 * This diagram shows the hierarchy of D3D SurfaceTypes:
 *
 *                               Any
 *                             /     \
 *                    D3DSurface     D3DTexture
 *                         |
 *                   D3DSurfaceRTT
 *
 * D3DSurface
 * This kind of surface can be rendered to using D3D APIs.  It is also
 * possible to copy a D3DSurface to another D3DSurface (or to itself).
 *
 * D3DTexture
 * This kind of surface cannot be rendered to using D3D (in the same sense
 * as in D3DSurface).  However, it is possible to upload a region of pixels
 * to a D3DTexture object via Lock/UnlockRect().  One can also copy a
 * surface of type D3DTexture to a D3DSurface by binding the texture
 * to a quad and then rendering it to the destination surface (this process
 * is known as "texture mapping").
 *
 * D3DSurfaceRTT
 * This kind of surface can be thought of as a sort of hybrid between
 * D3DSurface and D3DTexture, in that one can render to this kind of
 * surface as if it were of type D3DSurface, but the process of copying
 * this kind of surface to another is more like a D3DTexture.  (Note that
 * "RTT" stands for "render-to-texture".)
 *
 * In addition to these SurfaceType variants, we have also defined some
 * constants that describe in more detail the type of underlying D3D
 * surface.  This table helps explain the relationships between those
 * "type" constants and their corresponding SurfaceType:
 *
 * D3D Type          Corresponding SurfaceType
 * --------          -------------------------
 * RT_PLAIN          D3DSurface
 * TEXTURE           D3DTexture
 * FLIP_BACKBUFFER   D3DSurface
 * RT_TEXTURE        D3DSurfaceRTT
 */
public class D3DSurfaceData extends SurfaceData implements AccelSurface {

    /**
     * To be used with getNativeResource() only.
     * @see #getNativeResource()
     */
    public static final int D3D_DEVICE_RESOURCE= 100;
    /*
     * Surface types.
     * We use these surface types when copying from a sw surface
     * to a surface or texture.
     */
    public static final int ST_INT_ARGB        = 0;
    public static final int ST_INT_ARGB_PRE    = 1;
    public static final int ST_INT_ARGB_BM     = 2;
    public static final int ST_INT_RGB         = 3;
    public static final int ST_INT_BGR         = 4;
    public static final int ST_USHORT_565_RGB  = 5;
    public static final int ST_USHORT_555_RGB  = 6;
    public static final int ST_BYTE_INDEXED    = 7;
    public static final int ST_BYTE_INDEXED_BM = 8;

    /** Equals to D3DSWAPEFFECT_DISCARD */
    public static final int SWAP_DISCARD       = 1;
    /** Equals to D3DSWAPEFFECT_FLIP    */
    public static final int SWAP_FLIP          = 2;
    /** Equals to D3DSWAPEFFECT_COPY    */
    public static final int SWAP_COPY          = 3;
    /*
     * SurfaceTypes
     */
    private static final String DESC_D3D_SURFACE = "D3D Surface";
    private static final String DESC_D3D_SURFACE_RTT =
        "D3D Surface (render-to-texture)";
    private static final String DESC_D3D_TEXTURE = "D3D Texture";

    // REMIND: regarding ArgbPre??
    static final SurfaceType D3DSurface =
        SurfaceType.Any.deriveSubType(DESC_D3D_SURFACE,
                                      PixelConverter.ArgbPre.instance);
    static final SurfaceType D3DSurfaceRTT =
        D3DSurface.deriveSubType(DESC_D3D_SURFACE_RTT);
    static final SurfaceType D3DTexture =
        SurfaceType.Any.deriveSubType(DESC_D3D_TEXTURE);

    private int type;
    private int width, height;
    // these fields are set from the native code when the surface is
    // initialized
    private int nativeWidth, nativeHeight;
    protected WComponentPeer peer;
    private Image offscreenImage;
    protected D3DGraphicsDevice graphicsDevice;

    private int swapEffect;
    private VSyncType syncType;
    private int backBuffersNum;

    private WritableRasterNative wrn;

    protected static D3DRenderer d3dRenderPipe;
    protected static PixelToParallelogramConverter d3dTxRenderPipe;
    protected static ParallelogramPipe d3dAAPgramPipe;
    protected static D3DTextRenderer d3dTextPipe;
    protected static D3DDrawImage d3dImagePipe;

    private native boolean initTexture(long pData, boolean isRTT,
                                       boolean isOpaque);
    private native boolean initFlipBackbuffer(long pData, long pPeerData,
                                              int numbuffers,
                                              int swapEffect, int syncType);
    private native boolean initRTSurface(long pData, boolean isOpaque);
    private native void initOps(int screen, int width, int height);

    static {
        D3DRenderQueue rq = D3DRenderQueue.getInstance();
        d3dImagePipe = new D3DDrawImage();
        d3dTextPipe = new D3DTextRenderer(rq);
        d3dRenderPipe = new D3DRenderer(rq);
        if (GraphicsPrimitive.tracingEnabled()) {
            d3dTextPipe = d3dTextPipe.traceWrap();
            d3dRenderPipe = d3dRenderPipe.traceWrap();
            //The wrapped d3dRenderPipe will wrap the AA pipe as well...
            //d3dAAPgramPipe = d3dRenderPipe.traceWrap();
        }
        d3dAAPgramPipe = d3dRenderPipe.getAAParallelogramPipe();
        d3dTxRenderPipe =
            new PixelToParallelogramConverter(d3dRenderPipe, d3dRenderPipe,
                                              1.0, 0.25, true);

        D3DBlitLoops.register();
        D3DMaskFill.register();
        D3DMaskBlit.register();
    }

    protected D3DSurfaceData(WComponentPeer peer, D3DGraphicsConfig gc,
                             int width, int height, Image image,
                             ColorModel cm, int numBackBuffers,
                             int swapEffect, VSyncType vSyncType,
                             int type)
    {
        super(getCustomSurfaceType(type), cm);
        this.graphicsDevice = gc.getD3DDevice();
        this.peer = peer;
        this.type = type;
        this.width = width;
        this.height = height;
        this.offscreenImage = image;
        this.backBuffersNum = numBackBuffers;
        this.swapEffect = swapEffect;
        this.syncType = vSyncType;

        initOps(graphicsDevice.getScreen(), width, height);
        if (type == WINDOW) {
            // we put the surface into the "lost"
            // state; it will be restored by the D3DScreenUpdateManager
            // prior to rendering to it for the first time. This is done
            // so that vram is not wasted for surfaces never rendered to
            setSurfaceLost(true);
        } else {
            initSurface();
        }
        setBlitProxyKey(gc.getProxyKey());
    }

    @Override
    public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
        return D3DSurfaceDataProxy.
            createProxy(srcData,
                        (D3DGraphicsConfig)graphicsDevice.getDefaultConfiguration());
    }

    /**
     * Creates a SurfaceData object representing the back buffer of a
     * double-buffered on-screen Window.
     */
    public static D3DSurfaceData createData(WComponentPeer peer, Image image) {
        D3DGraphicsConfig gc = getGC(peer);
        if (gc == null || !peer.isAccelCapable()) {
            return null;
        }
        BufferCapabilities caps = peer.getBackBufferCaps();
        VSyncType vSyncType = VSYNC_DEFAULT;
        if (caps instanceof ExtendedBufferCapabilities) {
            vSyncType = ((ExtendedBufferCapabilities)caps).getVSync();
        }
        Rectangle r = peer.getBounds();
        BufferCapabilities.FlipContents flip = caps.getFlipContents();
        int swapEffect;
        if (flip == FlipContents.COPIED) {
            swapEffect = SWAP_COPY;
        } else if (flip == FlipContents.PRIOR) {
            swapEffect = SWAP_FLIP;
        } else { // flip == FlipContents.UNDEFINED || .BACKGROUND
            swapEffect = SWAP_DISCARD;
        }
        return new D3DSurfaceData(peer, gc, r.width, r.height,
                                  image, peer.getColorModel(),
                                  peer.getBackBuffersNum(),
                                  swapEffect, vSyncType, FLIP_BACKBUFFER);
    }

    /**
     * Returns a WINDOW type of surface - a
     * swap chain which serves as an on-screen surface,
     * handled by the D3DScreenUpdateManager.
     *
     * Note that the native surface is not initialized
     * when the surface is created to avoid using excessive
     * resources, and the surface is placed into the lost
     * state. It will be restored prior to any rendering
     * to it.
     *
     * @param peer peer for which the onscreen surface is to be created
     * @return a D3DWindowSurfaceData (flip chain) surface
     */
    public static D3DSurfaceData createData(WComponentPeer peer) {
        D3DGraphicsConfig gc = getGC(peer);
        if (gc == null || !peer.isAccelCapable()) {
            return null;
        }
        return new D3DWindowSurfaceData(peer, gc);
    }

    /**
     * Creates a SurfaceData object representing an off-screen buffer (either
     * a plain surface or Texture).
     */
    public static D3DSurfaceData createData(D3DGraphicsConfig gc,
                                            int width, int height,
                                            ColorModel cm,
                                            Image image, int type)
    {
        if (type == RT_TEXTURE) {
            boolean isOpaque = cm.getTransparency() == Transparency.OPAQUE;
            int cap = isOpaque ? CAPS_RT_TEXTURE_OPAQUE : CAPS_RT_TEXTURE_ALPHA;
            if (!gc.getD3DDevice().isCapPresent(cap)) {
                type = RT_PLAIN;
            }
        }
        D3DSurfaceData ret = null;
        try {
            ret = new D3DSurfaceData(null, gc, width, height,
                                     image, cm, 0, SWAP_DISCARD, VSYNC_DEFAULT,
                                     type);
        } catch (InvalidPipeException ipe) {
            // try again - we might have ran out of vram, and rt textures
            // could take up more than a plain surface, so it might succeed
            if (type == RT_TEXTURE) {
                // If a RT_TEXTURE was requested do not attempt to create a
                // plain surface. (note that RT_TEXTURE can only be requested
                // from a VI so the cast is safe)
                if (((SunVolatileImage)image).getForcedAccelSurfaceType() !=
                    RT_TEXTURE)
                {
                    type = RT_PLAIN;
                    ret = new D3DSurfaceData(null, gc, width, height,
                                             image, cm, 0, SWAP_DISCARD,
                                             VSYNC_DEFAULT, type);
                }
            }
        }
        return ret;
    }

    /**
     * Returns the appropriate SurfaceType corresponding to the given D3D
     * surface type constant (e.g. TEXTURE -> D3DTexture).
     */
    private static SurfaceType getCustomSurfaceType(int d3dType) {
        switch (d3dType) {
        case TEXTURE:
            return D3DTexture;
        case RT_TEXTURE:
            return D3DSurfaceRTT;
        default:
            return D3DSurface;
        }
    }

    private boolean initSurfaceNow() {
        boolean isOpaque = (getTransparency() == Transparency.OPAQUE);
        switch (type) {
            case RT_PLAIN:
                return initRTSurface(getNativeOps(), isOpaque);
            case TEXTURE:
                return initTexture(getNativeOps(), false/*isRTT*/, isOpaque);
            case RT_TEXTURE:
                return initTexture(getNativeOps(), true/*isRTT*/,  isOpaque);
            // REMIND: we may want to pass the exact type to the native
            // level here so that we could choose the right presentation
            // interval for the frontbuffer (immediate vs v-synced)
            case WINDOW:
            case FLIP_BACKBUFFER:
                return initFlipBackbuffer(getNativeOps(), peer.getData(),
                                          backBuffersNum, swapEffect,
                                          syncType.id());
            default:
                return false;
        }
    }

    /**
     * Initializes the appropriate D3D offscreen surface based on the value
     * of the type parameter.  If the surface creation fails for any reason,
     * an OutOfMemoryError will be thrown.
     */
    protected void initSurface() {
        // any time we create or restore the surface, recreate the raster
        synchronized (this) {
            wrn = null;
        }
        // REMIND: somewhere a puppy died
        class Status {
            boolean success = false;
        };
        final Status status = new Status();
        D3DRenderQueue rq = D3DRenderQueue.getInstance();
        rq.lock();
        try {
            rq.flushAndInvokeNow(new Runnable() {
                public void run() {
                    status.success = initSurfaceNow();
                }
            });
            if (!status.success) {
                throw new InvalidPipeException("Error creating D3DSurface");
            }
        } finally {
            rq.unlock();
        }
    }

    /**
     * Returns the D3DContext for the GraphicsConfig associated with this
     * surface.
     */
    public final D3DContext getContext() {
        return graphicsDevice.getContext();
    }

    /**
     * Returns one of the surface type constants defined above.
     */
    public final int getType() {
        return type;
    }

    private static native int  dbGetPixelNative(long pData, int x, int y);
    private static native void dbSetPixelNative(long pData, int x, int y,
                                                int pixel);
    static class D3DDataBufferNative extends DataBufferNative {
        int pixel;
        protected D3DDataBufferNative(SurfaceData sData,
                                      int type, int w, int h)
        {
            super(sData, type, w, h);
        }

        protected int getElem(final int x, final int y,
                              final SurfaceData sData)
        {
            int retPixel;
            D3DRenderQueue rq = D3DRenderQueue.getInstance();
            rq.lock();
            try {
                rq.flushAndInvokeNow(new Runnable() {
                    public void run() {
                        pixel = dbGetPixelNative(sData.getNativeOps(), x, y);
                    }
                });
            } finally {
                retPixel = pixel;
                rq.unlock();
            }
            return retPixel;
        }

        protected void setElem(final int x, final int y, final int pixel,
                               final SurfaceData sData)
        {
            D3DRenderQueue rq = D3DRenderQueue.getInstance();
            rq.lock();
            try {
                rq.flushAndInvokeNow(new Runnable() {
                    public void run() {
                        dbSetPixelNative(sData.getNativeOps(), x, y, pixel);
                    }
                });
                sData.markDirty();
            } finally {
                rq.unlock();
            }
        }
    }

    public synchronized Raster getRaster(int x, int y, int w, int h) {
        if (wrn == null) {
            DirectColorModel dcm = (DirectColorModel)getColorModel();
            SampleModel smHw;
            int dataType = 0;
            int scanStride = width;

            if (dcm.getPixelSize() == 24 || dcm.getPixelSize() == 32) {
                dataType = DataBuffer.TYPE_INT;
            } else {
                // 15, 16
                dataType = DataBuffer.TYPE_USHORT;
            }

            // note that we have to use the surface width and height here,
            // not the passed w,h
            smHw = new SinglePixelPackedSampleModel(dataType, width, height,
                                                    scanStride, dcm.getMasks());
            DataBuffer dbn = new D3DDataBufferNative(this, dataType,
                                                     width, height);
            wrn = WritableRasterNative.createNativeRaster(smHw, dbn);
        }

        return wrn;
    }

    /**
     * For now, we can only render LCD text if:
     *   - the pixel shaders are available, and
     *   - blending is disabled, and
     *   - the source color is opaque
     */
    public boolean canRenderLCDText(SunGraphics2D sg2d) {
        return
            graphicsDevice.isCapPresent(CAPS_LCD_SHADER) &&
            sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&
            sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR;
    }

    public void validatePipe(SunGraphics2D sg2d) {
        TextPipe textpipe;
        boolean validated = false;

        // REMIND: the D3D pipeline doesn't support XOR!, more
        // fixes will be needed below
        if (sg2d.compositeState >= sg2d.COMP_XOR) {
            super.validatePipe(sg2d);
            sg2d.imagepipe = d3dImagePipe;
            return;
        }

        // D3DTextRenderer handles both AA and non-AA text, but
        // only works with the following modes:
        // (Note: For LCD text we only enter this code path if
        // canRenderLCDText() has already validated that the mode is
        // CompositeType.SrcNoEa (opaque color), which will be subsumed
        // by the CompositeType.SrcNoEa (any color) test below.)

        if (/* CompositeType.SrcNoEa (any color) */
            (sg2d.compositeState <= sg2d.COMP_ISCOPY &&
             sg2d.paintState <= sg2d.PAINT_ALPHACOLOR)        ||

            /* CompositeType.SrcOver (any color) */
            (sg2d.compositeState == sg2d.COMP_ALPHA    &&
             sg2d.paintState <= sg2d.PAINT_ALPHACOLOR &&
             (((AlphaComposite)sg2d.composite).getRule() ==
              AlphaComposite.SRC_OVER))                       ||

            /* CompositeType.Xor (any color) */
            (sg2d.compositeState == sg2d.COMP_XOR &&
             sg2d.paintState <= sg2d.PAINT_ALPHACOLOR))
        {
            textpipe = d3dTextPipe;
        } else {
            // do this to initialize textpipe correctly; we will attempt
            // to override the non-text pipes below
            super.validatePipe(sg2d);
            textpipe = sg2d.textpipe;
            validated = true;
        }

        PixelToParallelogramConverter txPipe = null;
        D3DRenderer nonTxPipe = null;

        if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
            if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) {
                if (sg2d.compositeState <= sg2d.COMP_XOR) {
                    txPipe = d3dTxRenderPipe;
                    nonTxPipe = d3dRenderPipe;
                }
            } else if (sg2d.compositeState <= sg2d.COMP_ALPHA) {
                if (D3DPaints.isValid(sg2d)) {
                    txPipe = d3dTxRenderPipe;
                    nonTxPipe = d3dRenderPipe;
                }
                // custom paints handled by super.validatePipe() below
            }
        } else {
            if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) {
                if (graphicsDevice.isCapPresent(CAPS_AA_SHADER) &&
                    (sg2d.imageComp == CompositeType.SrcOverNoEa ||
                     sg2d.imageComp == CompositeType.SrcOver))
                {
                    if (!validated) {
                        super.validatePipe(sg2d);
                        validated = true;
                    }
                    PixelToParallelogramConverter aaConverter =
                        new PixelToParallelogramConverter(sg2d.shapepipe,
                                                          d3dAAPgramPipe,
                                                          1.0/8.0, 0.499,
                                                          false);
                    sg2d.drawpipe = aaConverter;
                    sg2d.fillpipe = aaConverter;
                    sg2d.shapepipe = aaConverter;
                } else if (sg2d.compositeState == sg2d.COMP_XOR) {
                    // install the solid pipes when AA and XOR are both enabled
                    txPipe = d3dTxRenderPipe;
                    nonTxPipe = d3dRenderPipe;
                }
            }
            // other cases handled by super.validatePipe() below
        }

        if (txPipe != null) {
            if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) {
                sg2d.drawpipe = txPipe;
                sg2d.fillpipe = txPipe;
            } else if (sg2d.strokeState != sg2d.STROKE_THIN) {
                sg2d.drawpipe = txPipe;
                sg2d.fillpipe = nonTxPipe;
            } else {
                sg2d.drawpipe = nonTxPipe;
                sg2d.fillpipe = nonTxPipe;
            }
            // Note that we use the transforming pipe here because it
            // will examine the shape and possibly perform an optimized
            // operation if it can be simplified.  The simplifications
            // will be valid for all STROKE and TRANSFORM types.
            sg2d.shapepipe = txPipe;
        } else {
            if (!validated) {
                super.validatePipe(sg2d);
            }
        }

        // install the text pipe based on our earlier decision
        sg2d.textpipe = textpipe;

        // always override the image pipe with the specialized D3D pipe
        sg2d.imagepipe = d3dImagePipe;
    }

    @Override
    protected MaskFill getMaskFill(SunGraphics2D sg2d) {
        if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR) {
            /*
             * We can only accelerate non-Color MaskFill operations if
             * all of the following conditions hold true:
             *   - there is an implementation for the given paintState
             *   - the current Paint can be accelerated for this destination
             *   - multitexturing is available (since we need to modulate
             *     the alpha mask texture with the paint texture)
             *
             * In all other cases, we return null, in which case the
             * validation code will choose a more general software-based loop.
             */
            if (!D3DPaints.isValid(sg2d) ||
                !graphicsDevice.isCapPresent(CAPS_MULTITEXTURE))
            {
                return null;
            }
        }
        return super.getMaskFill(sg2d);
    }

    @Override
    public boolean copyArea(SunGraphics2D sg2d,
                            int x, int y, int w, int h, int dx, int dy)
    {
        if (sg2d.transformState < sg2d.TRANSFORM_TRANSLATESCALE &&
            sg2d.compositeState < sg2d.COMP_XOR)
        {
            x += sg2d.transX;
            y += sg2d.transY;

            d3dRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy);

            return true;
        }
        return false;
    }

    @Override
    public void flush() {
        D3DRenderQueue rq = D3DRenderQueue.getInstance();
        rq.lock();
        try {
            RenderBuffer buf = rq.getBuffer();
            rq.ensureCapacityAndAlignment(12, 4);
            buf.putInt(FLUSH_SURFACE);
            buf.putLong(getNativeOps());

            // this call is expected to complete synchronously, so flush now
            rq.flushNow();
        } finally {
            rq.unlock();
        }
    }

    /**
     * Disposes the native resources associated with the given D3DSurfaceData
     * (referenced by the pData parameter).  This method is invoked from
     * the native Dispose() method from the Disposer thread when the
     * Java-level D3DSurfaceData object is about to go away.
     */
    static void dispose(long pData) {
        D3DRenderQueue rq = D3DRenderQueue.getInstance();
        rq.lock();
        try {
            RenderBuffer buf = rq.getBuffer();
            rq.ensureCapacityAndAlignment(12, 4);
            buf.putInt(DISPOSE_SURFACE);
            buf.putLong(pData);

            // this call is expected to complete synchronously, so flush now
            rq.flushNow();
        } finally {
            rq.unlock();
        }
    }

    static void swapBuffers(D3DSurfaceData sd,
                            final int x1, final int y1,
                            final int x2, final int y2)
    {
        long pData = sd.getNativeOps();
        D3DRenderQueue rq = D3DRenderQueue.getInstance();
        // swapBuffers can be called from the toolkit thread by swing, we
        // should detect this and prevent the deadlocks
        if (rq.isRenderQueueThread()) {
            if (!rq.tryLock()) {
                // if we could not obtain the lock, repaint the area
                // that was supposed to be swapped, and no-op this swap
                final Component target = (Component)sd.getPeer().getTarget();
                SunToolkit.executeOnEventHandlerThread(target, new Runnable() {
                    public void run() {
                        target.repaint(x1, y1, x2, y2);
                    }
                });
                return;
            }
        } else {
            rq.lock();
        }
        try {
            RenderBuffer buf = rq.getBuffer();
            rq.ensureCapacityAndAlignment(28, 4);
            buf.putInt(SWAP_BUFFERS);
            buf.putLong(pData);
            buf.putInt(x1);
            buf.putInt(y1);
            buf.putInt(x2);
            buf.putInt(y2);
            rq.flushNow();
        } finally {
            rq.unlock();
        }
    }

    /**
     * Returns destination Image associated with this SurfaceData.
     */
    public Object getDestination() {
        return offscreenImage;
    }

    public Rectangle getBounds() {
        if (type == FLIP_BACKBUFFER || type == WINDOW) {
            Rectangle r = peer.getBounds();
            r.x = r.y = 0;
            return r;
        } else {
            return new Rectangle(width, height);
        }
    }

    public Rectangle getNativeBounds() {
        D3DRenderQueue rq = D3DRenderQueue.getInstance();
        // need to lock to make sure nativeWidth and Height are consistent
        // since they are set from the render thread from the native
        // level
        rq.lock();
        try {
            // REMIND: use xyoffsets?
            return new Rectangle(nativeWidth, nativeHeight);
        } finally {
            rq.unlock();
        }
    }


    public GraphicsConfiguration getDeviceConfiguration() {
        return graphicsDevice.getDefaultConfiguration();
    }

    public SurfaceData getReplacement() {
        return restoreContents(offscreenImage);
    }

    private static D3DGraphicsConfig getGC(WComponentPeer peer) {
        GraphicsConfiguration gc;
        if (peer != null) {
            gc =  peer.getGraphicsConfiguration();
        } else {
            GraphicsEnvironment env =
                    GraphicsEnvironment.getLocalGraphicsEnvironment();
            GraphicsDevice gd = env.getDefaultScreenDevice();
            gc = gd.getDefaultConfiguration();
        }
        return (gc instanceof D3DGraphicsConfig) ? (D3DGraphicsConfig)gc : null;
    }

    /**
     * Attempts to restore the surface by initializing the native data
     */
    void restoreSurface() {
        initSurface();
    }

    WComponentPeer getPeer() {
        return peer;
    }

    /**
     * We need to let the surface manager know that the surface is lost so
     * that for example BufferStrategy.contentsLost() returns correct result.
     * Normally the status of contentsLost is set in validate(), but in some
     * cases (like Swing's buffer per window) we intentionally don't call
     * validate from the toolkit thread but only check for the BS status.
     */
    @Override
    public void setSurfaceLost(boolean lost) {
        super.setSurfaceLost(lost);
        if (lost && offscreenImage != null) {
            SurfaceManager sm = SurfaceManager.getManager(offscreenImage);
            sm.acceleratedSurfaceLost();
        }
    }

    private static native long getNativeResourceNative(long sdops, int resType);
    /**
     * Returns a pointer to the native resource of specified {@code resType}
     * associated with this surface.
     *
     * Specifically, for {@code D3DSurfaceData} this method returns pointers of
     * the following:
     * <pre>
     * TEXTURE              - (IDirect3DTexture9*)
     * RT_TEXTURE, RT_PLAIN - (IDirect3DSurface9*)
     * FLIP_BACKBUFFER      - (IDirect3DSwapChain9*)
     * D3D_DEVICE_RESOURCE  - (IDirect3DDevice9*)
     * </pre>
     *
     * Multiple resources may be available for some types (i.e. for render to
     * texture one could retrieve both a destination surface by specifying
     * RT_TEXTURE, and a texture by using TEXTURE).
     *
     * Note: the pointer returned by this method is only valid on the rendering
     * thread.
     *
     * @return pointer to the native resource of specified type or 0L if
     * such resource doesn't exist or can not be retrieved.
     * @see sun.java2d.pipe.hw.AccelSurface#getNativeResource
     */
    public long getNativeResource(int resType) {
        return getNativeResourceNative(getNativeOps(), resType);
    }

    /**
     * Class representing an on-screen d3d surface. Since d3d can't
     * render to the screen directly, it is implemented as a swap chain,
     * controlled by D3DScreenUpdateManager.
     *
     * @see D3DScreenUpdateManager
     */
    public static class D3DWindowSurfaceData extends D3DSurfaceData {
        StateTracker dirtyTracker;

        public D3DWindowSurfaceData(WComponentPeer peer,
                                    D3DGraphicsConfig gc)
        {
            super(peer, gc,
                  peer.getBounds().width, peer.getBounds().height,
                  null, peer.getColorModel(), 1, SWAP_COPY, VSYNC_DEFAULT,
                  WINDOW);
            dirtyTracker = getStateTracker();
        }

        /**
         * {@inheritDoc}
         *
         * Overridden to use ScreenUpdateManager to obtain the replacement
         * surface.
         *
         * @see sun.java2d.ScreenUpdateManager#getReplacementScreenSurface
         */
        @Override
        public SurfaceData getReplacement() {
            ScreenUpdateManager mgr = ScreenUpdateManager.getInstance();
            return mgr.getReplacementScreenSurface(peer, this);
        }

        /**
         * Returns destination Component associated with this SurfaceData.
         */
        @Override
        public Object getDestination() {
            return peer.getTarget();
        }

        @Override
        void restoreSurface() {
            Window fsw = graphicsDevice.getFullScreenWindow();
            if (fsw != null && fsw != peer.getTarget()) {
                throw new InvalidPipeException("Can't restore onscreen surface"+
                                               " when in full-screen mode");
            }
            super.restoreSurface();
            // if initialization was unsuccessful, an IPE will be thrown
            // and the surface will remain lost
            setSurfaceLost(false);

            // This is to make sure the render target is reset after this
            // surface is restored. The reason for this is that sometimes this
            // surface can be restored from multiple threads (the screen update
            // manager's thread and app's rendering thread) at the same time,
            // and when that happens the second restoration will create the
            // native resource which will not be set as render target because
            // the BufferedContext's validate method will think that since the
            // surface data object didn't change then the current render target
            // is correct and no rendering will appear on the screen.
            D3DRenderQueue rq = D3DRenderQueue.getInstance();
            rq.lock();
            try {
                getContext().invalidateContext();
            } finally {
                rq.unlock();
            }
        }

        public boolean isDirty() {
            return !dirtyTracker.isCurrent();
        }

        public void markClean() {
            dirtyTracker = getStateTracker();
        }
    }

    /**
     * Updates the layered window with the contents of the surface.
     *
     * @param pd3dsd pointer to the D3DSDOps structure
     * @param pData pointer to the AwtWindow peer data
     * @param w width of the window
     * @param h height of the window
     * @see sun.awt.windows.TranslucentWindowPainter
     */
    public static native boolean updateWindowAccelImpl(long pd3dsd, long pData,
                                                       int w, int h);
}