1 /*
2  * Copyright (c) 2004, 2016, 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.opengl;
27 
28 import java.awt.AWTException;
29 import java.awt.BufferCapabilities;
30 import java.awt.Color;
31 import java.awt.Component;
32 import java.awt.Graphics;
33 import java.awt.Graphics2D;
34 import java.awt.ImageCapabilities;
35 import java.awt.Transparency;
36 import java.awt.color.ColorSpace;
37 import java.awt.image.ColorModel;
38 import java.awt.image.DataBuffer;
39 import java.awt.image.DirectColorModel;
40 import java.awt.image.VolatileImage;
41 import sun.awt.Win32GraphicsConfig;
42 import sun.awt.Win32GraphicsDevice;
43 import sun.awt.image.SunVolatileImage;
44 import sun.awt.image.SurfaceManager;
45 import sun.awt.windows.WComponentPeer;
46 import sun.java2d.Disposer;
47 import sun.java2d.DisposerRecord;
48 import sun.java2d.SunGraphics2D;
49 import sun.java2d.Surface;
50 import sun.java2d.SurfaceData;
51 import sun.java2d.pipe.hw.AccelSurface;
52 import sun.java2d.pipe.hw.AccelTypedVolatileImage;
53 import sun.java2d.pipe.hw.ContextCapabilities;
54 import static sun.java2d.opengl.OGLContext.OGLContextCaps.*;
55 import static sun.java2d.opengl.WGLSurfaceData.*;
56 import sun.java2d.opengl.OGLContext.OGLContextCaps;
57 import sun.java2d.windows.GDIWindowSurfaceData;
58 
59 public class WGLGraphicsConfig
60     extends Win32GraphicsConfig
61     implements OGLGraphicsConfig
62 {
63     protected static boolean wglAvailable;
64     private static ImageCapabilities imageCaps = new WGLImageCaps();
65 
66     private BufferCapabilities bufferCaps;
67     private long pConfigInfo;
68     private ContextCapabilities oglCaps;
69     private OGLContext context;
70     private Object disposerReferent = new Object();
71 
getDefaultPixFmt(int screennum)72     public static native int getDefaultPixFmt(int screennum);
initWGL()73     private static native boolean initWGL();
getWGLConfigInfo(int screennum, int visualnum)74     private static native long getWGLConfigInfo(int screennum, int visualnum);
getOGLCapabilities(long configInfo)75     private static native int getOGLCapabilities(long configInfo);
76 
77     static {
78         wglAvailable = initWGL();
79     }
80 
81     @SuppressWarnings("deprecation")
WGLGraphicsConfig(Win32GraphicsDevice device, int visualnum, long configInfo, ContextCapabilities oglCaps)82     protected WGLGraphicsConfig(Win32GraphicsDevice device, int visualnum,
83                                 long configInfo, ContextCapabilities oglCaps)
84     {
85         super(device, visualnum);
86         this.pConfigInfo = configInfo;
87         this.oglCaps = oglCaps;
88         context = new OGLContext(OGLRenderQueue.getInstance(), this);
89 
90         // add a record to the Disposer so that we destroy the native
91         // WGLGraphicsConfigInfo data when this object goes away
92         Disposer.addRecord(disposerReferent,
93                            new WGLGCDisposerRecord(pConfigInfo));
94     }
95 
getProxyKey()96     public Object getProxyKey() {
97         return this;
98     }
99 
createManagedSurface(int w, int h, int transparency)100     public SurfaceData createManagedSurface(int w, int h, int transparency) {
101         return WGLSurfaceData.createData(this, w, h,
102                                          getColorModel(transparency),
103                                          null,
104                                          OGLSurfaceData.TEXTURE);
105     }
106 
getConfig(Win32GraphicsDevice device, int pixfmt)107     public static WGLGraphicsConfig getConfig(Win32GraphicsDevice device,
108                                               int pixfmt)
109     {
110         if (!wglAvailable) {
111             return null;
112         }
113 
114         long cfginfo = 0;
115         final String ids[] = new String[1];
116         OGLRenderQueue rq = OGLRenderQueue.getInstance();
117         rq.lock();
118         try {
119             // getWGLConfigInfo() creates and destroys temporary
120             // surfaces/contexts, so we should first invalidate the current
121             // Java-level context and flush the queue...
122             OGLContext.invalidateCurrentContext();
123             WGLGetConfigInfo action =
124                 new WGLGetConfigInfo(device.getScreen(), pixfmt);
125             rq.flushAndInvokeNow(action);
126             cfginfo = action.getConfigInfo();
127             if (cfginfo != 0L) {
128                 OGLContext.setScratchSurface(cfginfo);
129                 rq.flushAndInvokeNow(new Runnable() {
130                     public void run() {
131                         ids[0] = OGLContext.getOGLIdString();
132                     }
133                 });
134             }
135         } finally {
136             rq.unlock();
137         }
138         if (cfginfo == 0) {
139             return null;
140         }
141 
142         int oglCaps = getOGLCapabilities(cfginfo);
143         ContextCapabilities caps = new OGLContextCaps(oglCaps, ids[0]);
144 
145         return new WGLGraphicsConfig(device, pixfmt, cfginfo, caps);
146     }
147 
148     /**
149      * This is a small helper class that allows us to execute
150      * getWGLConfigInfo() on the queue flushing thread.
151      */
152     private static class WGLGetConfigInfo implements Runnable {
153         private int screen;
154         private int pixfmt;
155         private long cfginfo;
WGLGetConfigInfo(int screen, int pixfmt)156         private WGLGetConfigInfo(int screen, int pixfmt) {
157             this.screen = screen;
158             this.pixfmt = pixfmt;
159         }
run()160         public void run() {
161             cfginfo = getWGLConfigInfo(screen, pixfmt);
162         }
getConfigInfo()163         public long getConfigInfo() {
164             return cfginfo;
165         }
166     }
167 
isWGLAvailable()168     public static boolean isWGLAvailable() {
169         return wglAvailable;
170     }
171 
172     /**
173      * Returns true if the provided capability bit is present for this config.
174      * See OGLContext.java for a list of supported capabilities.
175      */
176     @Override
isCapPresent(int cap)177     public final boolean isCapPresent(int cap) {
178         return ((oglCaps.getCaps() & cap) != 0);
179     }
180 
181     @Override
getNativeConfigInfo()182     public final long getNativeConfigInfo() {
183         return pConfigInfo;
184     }
185 
186     /**
187      * {@inheritDoc}
188      *
189      * @see sun.java2d.pipe.hw.BufferedContextProvider#getContext
190      */
191     @Override
getContext()192     public final OGLContext getContext() {
193         return context;
194     }
195 
196     private static class WGLGCDisposerRecord implements DisposerRecord {
197         private long pCfgInfo;
WGLGCDisposerRecord(long pCfgInfo)198         public WGLGCDisposerRecord(long pCfgInfo) {
199             this.pCfgInfo = pCfgInfo;
200         }
dispose()201         public void dispose() {
202             if (pCfgInfo != 0) {
203                 OGLRenderQueue.disposeGraphicsConfig(pCfgInfo);
204                 pCfgInfo = 0;
205             }
206         }
207     }
208 
209     @Override
displayChanged()210     public synchronized void displayChanged() {
211         super.displayChanged();
212         // the context could hold a reference to a WGLSurfaceData, which in
213         // turn has a reference back to this WGLGraphicsConfig, so in order
214         // for this instance to be disposed we need to break the connection
215         OGLRenderQueue rq = OGLRenderQueue.getInstance();
216         rq.lock();
217         try {
218             OGLContext.invalidateCurrentContext();
219         } finally {
220             rq.unlock();
221         }
222     }
223 
224     @Override
getColorModel(int transparency)225     public ColorModel getColorModel(int transparency) {
226         switch (transparency) {
227         case Transparency.OPAQUE:
228             // REMIND: once the ColorModel spec is changed, this should be
229             //         an opaque premultiplied DCM...
230             return new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
231         case Transparency.BITMASK:
232             return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000);
233         case Transparency.TRANSLUCENT:
234             ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
235             return new DirectColorModel(cs, 32,
236                                         0xff0000, 0xff00, 0xff, 0xff000000,
237                                         true, DataBuffer.TYPE_INT);
238         default:
239             return null;
240         }
241     }
242 
243     @Override
toString()244     public String toString() {
245         return ("WGLGraphicsConfig[dev="+screen+",pixfmt="+visual+"]");
246     }
247 
248     /**
249      * The following methods are invoked from WComponentPeer.java rather
250      * than having the Win32-dependent implementations hardcoded in that
251      * class.  This way the appropriate actions are taken based on the peer's
252      * GraphicsConfig, whether it is a Win32GraphicsConfig or a
253      * WGLGraphicsConfig.
254      */
255 
256     /**
257      * Creates a new SurfaceData that will be associated with the given
258      * WComponentPeer.
259      */
260     @Override
createSurfaceData(WComponentPeer peer, int numBackBuffers)261     public SurfaceData createSurfaceData(WComponentPeer peer,
262                                          int numBackBuffers)
263     {
264         SurfaceData sd = WGLSurfaceData.createData(peer);
265         if (sd == null) {
266             sd = GDIWindowSurfaceData.createData(peer);
267         }
268         return sd;
269     }
270 
271     /**
272      * The following methods correspond to the multibuffering methods in
273      * WComponentPeer.java...
274      */
275 
276     /**
277      * Checks that the requested configuration is natively supported; if not,
278      * an AWTException is thrown.
279      */
280     @Override
assertOperationSupported(Component target, int numBuffers, BufferCapabilities caps)281     public void assertOperationSupported(Component target,
282                                          int numBuffers,
283                                          BufferCapabilities caps)
284         throws AWTException
285     {
286         if (numBuffers > 2) {
287             throw new AWTException(
288                 "Only double or single buffering is supported");
289         }
290         BufferCapabilities configCaps = getBufferCapabilities();
291         if (!configCaps.isPageFlipping()) {
292             throw new AWTException("Page flipping is not supported");
293         }
294         if (caps.getFlipContents() == BufferCapabilities.FlipContents.PRIOR) {
295             throw new AWTException("FlipContents.PRIOR is not supported");
296         }
297     }
298 
299     /**
300      * Creates a WGL-based backbuffer for the given peer and returns the
301      * image wrapper.
302      */
303     @Override
createBackBuffer(WComponentPeer peer)304     public VolatileImage createBackBuffer(WComponentPeer peer) {
305         Component target = (Component)peer.getTarget();
306         // it is possible for the component to have size 0x0, adjust it to
307         // be at least 1x1 to avoid IAE
308         int w = Math.max(1, target.getWidth());
309         int h = Math.max(1, target.getHeight());
310         return new SunVolatileImage(target,
311                                     w, h,
312                                     Boolean.TRUE);
313     }
314 
315     /**
316      * Performs the native WGL flip operation for the given target Component.
317      */
318     @Override
flip(WComponentPeer peer, Component target, VolatileImage backBuffer, int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction)319     public void flip(WComponentPeer peer,
320                      Component target, VolatileImage backBuffer,
321                      int x1, int y1, int x2, int y2,
322                      BufferCapabilities.FlipContents flipAction)
323     {
324         if (flipAction == BufferCapabilities.FlipContents.COPIED) {
325             SurfaceManager vsm = SurfaceManager.getManager(backBuffer);
326             SurfaceData sd = vsm.getPrimarySurfaceData();
327 
328             if (sd instanceof WGLVSyncOffScreenSurfaceData) {
329                 WGLVSyncOffScreenSurfaceData vsd =
330                     (WGLVSyncOffScreenSurfaceData)sd;
331                 SurfaceData bbsd = vsd.getFlipSurface();
332                 Graphics2D bbg =
333                     new SunGraphics2D(bbsd, Color.black, Color.white, null);
334                 try {
335                     bbg.drawImage(backBuffer, 0, 0, null);
336                 } finally {
337                     bbg.dispose();
338                 }
339             } else {
340                 Graphics g = peer.getGraphics();
341                 try {
342                     g.drawImage(backBuffer,
343                                 x1, y1, x2, y2,
344                                 x1, y1, x2, y2,
345                                 null);
346                 } finally {
347                     g.dispose();
348                 }
349                 return;
350             }
351         } else if (flipAction == BufferCapabilities.FlipContents.PRIOR) {
352             // not supported by WGL...
353             return;
354         }
355 
356         OGLSurfaceData.swapBuffers(peer.getData());
357 
358         if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) {
359             Graphics g = backBuffer.getGraphics();
360             try {
361                 g.setColor(target.getBackground());
362                 g.fillRect(0, 0,
363                            backBuffer.getWidth(),
364                            backBuffer.getHeight());
365             } finally {
366                 g.dispose();
367             }
368         }
369     }
370 
371     private static class WGLBufferCaps extends BufferCapabilities {
WGLBufferCaps(boolean dblBuf)372         public WGLBufferCaps(boolean dblBuf) {
373             super(imageCaps, imageCaps,
374                   dblBuf ? FlipContents.UNDEFINED : null);
375         }
376     }
377 
378     @Override
getBufferCapabilities()379     public BufferCapabilities getBufferCapabilities() {
380         if (bufferCaps == null) {
381             boolean dblBuf = isCapPresent(CAPS_DOUBLEBUFFERED);
382             bufferCaps = new WGLBufferCaps(dblBuf);
383         }
384         return bufferCaps;
385     }
386 
387     private static class WGLImageCaps extends ImageCapabilities {
WGLImageCaps()388         private WGLImageCaps() {
389             super(true);
390         }
isTrueVolatile()391         public boolean isTrueVolatile() {
392             return true;
393         }
394     }
395 
396     @Override
getImageCapabilities()397     public ImageCapabilities getImageCapabilities() {
398         return imageCaps;
399     }
400 
401     /**
402      * {@inheritDoc}
403      *
404      * @see sun.java2d.pipe.hw.AccelGraphicsConfig#createCompatibleVolatileImage
405      */
406     @Override
407     public VolatileImage
createCompatibleVolatileImage(int width, int height, int transparency, int type)408         createCompatibleVolatileImage(int width, int height,
409                                       int transparency, int type)
410     {
411         if ((type != FBOBJECT && type != TEXTURE)
412                 || transparency == Transparency.BITMASK
413                 || type == FBOBJECT && !isCapPresent(CAPS_EXT_FBOBJECT)) {
414             return null;
415         }
416         SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height,
417                                                           transparency, type);
418         Surface sd = vi.getDestSurface();
419         if (!(sd instanceof AccelSurface) ||
420             ((AccelSurface)sd).getType() != type)
421         {
422             vi.flush();
423             vi = null;
424         }
425 
426         return vi;
427     }
428 
429     /**
430      * {@inheritDoc}
431      *
432      * @see sun.java2d.pipe.hw.AccelGraphicsConfig#getContextCapabilities
433      */
434     @Override
getContextCapabilities()435     public ContextCapabilities getContextCapabilities() {
436         return oglCaps;
437     }
438 }
439