1 /*
2  * Copyright (c) 2007, 2008, 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.AWTException;
29 import java.awt.BufferCapabilities;
30 import java.awt.BufferCapabilities.FlipContents;
31 import java.awt.Component;
32 import java.awt.Graphics;
33 import java.awt.ImageCapabilities;
34 import java.awt.Transparency;
35 import java.awt.color.ColorSpace;
36 import java.awt.image.ColorModel;
37 import java.awt.image.DataBuffer;
38 import java.awt.image.DirectColorModel;
39 import java.awt.image.VolatileImage;
40 import sun.awt.Win32GraphicsConfig;
41 import sun.awt.image.SunVolatileImage;
42 import sun.awt.image.SurfaceManager;
43 import sun.awt.windows.WComponentPeer;
44 import sun.java2d.Surface;
45 import sun.java2d.SurfaceData;
46 import sun.java2d.pipe.hw.AccelDeviceEventNotifier;
47 import sun.java2d.pipe.hw.AccelTypedVolatileImage;
48 import sun.java2d.pipe.hw.AccelGraphicsConfig;
49 import sun.java2d.pipe.hw.AccelSurface;
50 import sun.java2d.pipe.hw.ContextCapabilities;
51 import static sun.java2d.pipe.hw.AccelSurface.*;
52 import static sun.java2d.d3d.D3DContext.D3DContextCaps.*;
53 import sun.java2d.pipe.hw.AccelDeviceEventListener;
54 
55 public class D3DGraphicsConfig
56     extends Win32GraphicsConfig
57     implements AccelGraphicsConfig
58 {
59     private static ImageCapabilities imageCaps = new D3DImageCaps();
60 
61     private BufferCapabilities bufferCaps;
62     private D3DGraphicsDevice device;
63 
D3DGraphicsConfig(D3DGraphicsDevice device)64     protected D3DGraphicsConfig(D3DGraphicsDevice device) {
65         super(device, 0);
66         this.device = device;
67     }
68 
createManagedSurface(int w, int h, int transparency)69     public SurfaceData createManagedSurface(int w, int h, int transparency) {
70         return D3DSurfaceData.createData(this, w, h,
71                                          getColorModel(transparency),
72                                          null,
73                                          D3DSurfaceData.TEXTURE);
74     }
75 
76     @Override
displayChanged()77     public synchronized void displayChanged() {
78         super.displayChanged();
79         // the context could hold a reference to a D3DSurfaceData, which in
80         // turn has a reference back to this D3DGraphicsConfig, so in order
81         // for this instance to be disposed we need to break the connection
82         D3DRenderQueue rq = D3DRenderQueue.getInstance();
83         rq.lock();
84         try {
85             D3DContext.invalidateCurrentContext();
86         } finally {
87             rq.unlock();
88         }
89     }
90 
91     @Override
getColorModel(int transparency)92     public ColorModel getColorModel(int transparency) {
93         switch (transparency) {
94         case Transparency.OPAQUE:
95             // REMIND: once the ColorModel spec is changed, this should be
96             //         an opaque premultiplied DCM...
97             return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
98         case Transparency.BITMASK:
99             return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
100         case Transparency.TRANSLUCENT:
101             ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
102             return new DirectColorModel(cs, 32,
103                                         0xff0000, 0xff00, 0xff, 0xff000000,
104                                         true, DataBuffer.TYPE_INT);
105         default:
106             return null;
107         }
108     }
109 
110     @Override
toString()111     public String toString() {
112         return ("D3DGraphicsConfig[dev="+screen+",pixfmt="+visual+"]");
113     }
114 
115     /**
116      * The following methods are invoked from WComponentPeer.java rather
117      * than having the Win32-dependent implementations hardcoded in that
118      * class.  This way the appropriate actions are taken based on the peer's
119      * GraphicsConfig, whether it is a Win32GraphicsConfig or a
120      * D3DGraphicsConfig.
121      */
122 
123     /**
124      * Creates a new SurfaceData that will be associated with the given
125      * WComponentPeer. D3D9 doesn't allow rendering to the screen,
126      * so a GDI surface will be returned.
127      */
128     @Override
createSurfaceData(WComponentPeer peer, int numBackBuffers)129     public SurfaceData createSurfaceData(WComponentPeer peer,
130                                          int numBackBuffers)
131     {
132         return super.createSurfaceData(peer, numBackBuffers);
133     }
134 
135     /**
136      * The following methods correspond to the multibuffering methods in
137      * WComponentPeer.java...
138      */
139 
140     /**
141      * Checks that the requested configuration is natively supported; if not,
142      * an AWTException is thrown.
143      */
144     @Override
assertOperationSupported(Component target, int numBuffers, BufferCapabilities caps)145     public void assertOperationSupported(Component target,
146                                          int numBuffers,
147                                          BufferCapabilities caps)
148         throws AWTException
149     {
150         if (numBuffers < 2 || numBuffers > 4) {
151             throw new AWTException("Only 2-4 buffers supported");
152         }
153         if (caps.getFlipContents() == BufferCapabilities.FlipContents.COPIED &&
154             numBuffers != 2)
155         {
156             throw new AWTException("FlipContents.COPIED is only" +
157                                    "supported for 2 buffers");
158         }
159     }
160 
161     /**
162      * Creates a D3D-based backbuffer for the given peer and returns the
163      * image wrapper.
164      */
165     @Override
createBackBuffer(WComponentPeer peer)166     public VolatileImage createBackBuffer(WComponentPeer peer) {
167         Component target = (Component)peer.getTarget();
168         // it is possible for the component to have size 0x0, adjust it to
169         // be at least 1x1 to avoid IAE
170         int w = Math.max(1, target.getWidth());
171         int h = Math.max(1, target.getHeight());
172         return new SunVolatileImage(target, w, h, Boolean.TRUE);
173     }
174 
175     /**
176      * Performs the native D3D flip operation for the given target Component.
177      */
178     @Override
flip(WComponentPeer peer, Component target, VolatileImage backBuffer, int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction)179     public void flip(WComponentPeer peer,
180                      Component target, VolatileImage backBuffer,
181                      int x1, int y1, int x2, int y2,
182                      BufferCapabilities.FlipContents flipAction)
183     {
184         // REMIND: we should actually get a surface data for the
185         // backBuffer's VI
186         SurfaceManager d3dvsm =
187             SurfaceManager.getManager(backBuffer);
188         SurfaceData sd = d3dvsm.getPrimarySurfaceData();
189         if (sd instanceof D3DSurfaceData) {
190             D3DSurfaceData d3dsd = (D3DSurfaceData)sd;
191             D3DSurfaceData.swapBuffers(d3dsd, x1, y1, x2, y2);
192         } else {
193             // the surface was likely lost could not have been restored
194             Graphics g = peer.getGraphics();
195             try {
196                 g.drawImage(backBuffer,
197                             x1, y1, x2, y2,
198                             x1, y1, x2, y2,
199                             null);
200             } finally {
201                 g.dispose();
202             }
203         }
204 
205         if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) {
206             Graphics g = backBuffer.getGraphics();
207             try {
208                 g.setColor(target.getBackground());
209                 g.fillRect(0, 0,
210                            backBuffer.getWidth(),
211                            backBuffer.getHeight());
212             } finally {
213                 g.dispose();
214             }
215         }
216     }
217 
218     private static class D3DBufferCaps extends BufferCapabilities {
D3DBufferCaps()219         public D3DBufferCaps() {
220             // REMIND: should we indicate that the front-buffer
221             // (the on-screen rendering) is not accelerated?
222             super(imageCaps, imageCaps, FlipContents.UNDEFINED);
223         }
224         @Override
isMultiBufferAvailable()225         public boolean isMultiBufferAvailable() {
226             return true;
227         }
228 
229     }
230 
231     @Override
getBufferCapabilities()232     public BufferCapabilities getBufferCapabilities() {
233         if (bufferCaps == null) {
234             bufferCaps = new D3DBufferCaps();
235         }
236         return bufferCaps;
237     }
238 
239     private static class D3DImageCaps extends ImageCapabilities {
D3DImageCaps()240         private D3DImageCaps() {
241             super(true);
242         }
243         @Override
isTrueVolatile()244         public boolean isTrueVolatile() {
245             return true;
246         }
247     }
248 
249     @Override
getImageCapabilities()250     public ImageCapabilities getImageCapabilities() {
251         return imageCaps;
252     }
253 
getD3DDevice()254     D3DGraphicsDevice getD3DDevice() {
255         return device;
256     }
257 
258     /**
259      * {@inheritDoc}
260      *
261      * @see sun.java2d.pipe.hw.BufferedContextProvider#getContext
262      */
263     @Override
getContext()264     public D3DContext getContext() {
265         return device.getContext();
266     }
267 
268     /**
269      * {@inheritDoc}
270      *
271      * @see sun.java2d.pipe.hw.AccelGraphicsConfig#createCompatibleVolatileImage
272      */
273     @Override
274     public VolatileImage
createCompatibleVolatileImage(int width, int height, int transparency, int type)275         createCompatibleVolatileImage(int width, int height,
276                                       int transparency, int type)
277     {
278         if (type == FLIP_BACKBUFFER || type == WINDOW || type == UNDEFINED ||
279             transparency == Transparency.BITMASK)
280         {
281             return null;
282         }
283         boolean isOpaque = transparency == Transparency.OPAQUE;
284         if (type == RT_TEXTURE) {
285             int cap = isOpaque ? CAPS_RT_TEXTURE_OPAQUE : CAPS_RT_TEXTURE_ALPHA;
286             if (!device.isCapPresent(cap)) {
287                 return null;
288             }
289         } else if (type == RT_PLAIN) {
290             if (!isOpaque && !device.isCapPresent(CAPS_RT_PLAIN_ALPHA)) {
291                 return null;
292             }
293         }
294 
295         SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,
296                                                           transparency, type);
297         Surface sd = vi.getDestSurface();
298         if (!(sd instanceof AccelSurface) ||
299             ((AccelSurface)sd).getType() != type)
300         {
301             vi.flush();
302             vi = null;
303         }
304 
305         return vi;
306     }
307 
308     /**
309      * {@inheritDoc}
310      *
311      * @see sun.java2d.pipe.hw.AccelGraphicsConfig#getContextCapabilities
312      */
313     @Override
getContextCapabilities()314     public ContextCapabilities getContextCapabilities() {
315         return device.getContextCapabilities();
316     }
317 
318     @Override
addDeviceEventListener(AccelDeviceEventListener l)319     public void addDeviceEventListener(AccelDeviceEventListener l) {
320         AccelDeviceEventNotifier.addListener(l, device.getScreen());
321     }
322 
323     @Override
removeDeviceEventListener(AccelDeviceEventListener l)324     public void removeDeviceEventListener(AccelDeviceEventListener l) {
325         AccelDeviceEventNotifier.removeListener(l);
326     }
327 }
328