1 /* 2 * Copyright (c) 2004, 2015, 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 72 public static native int getDefaultPixFmt(int screennum); 73 private static native boolean initWGL(); 74 private static native long getWGLConfigInfo(int screennum, int visualnum); 75 private static native int getOGLCapabilities(long configInfo); 76 77 static { 78 wglAvailable = initWGL(); 79 } 80 81 @SuppressWarnings("deprecation") 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 96 public Object getProxyKey() { 97 return this; 98 } 99 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 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; 156 private WGLGetConfigInfo(int screen, int pixfmt) { 157 this.screen = screen; 158 this.pixfmt = pixfmt; 159 } 160 public void run() { 161 cfginfo = getWGLConfigInfo(screen, pixfmt); 162 } 163 public long getConfigInfo() { 164 return cfginfo; 165 } 166 } 167 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 177 public final boolean isCapPresent(int cap) { 178 return ((oglCaps.getCaps() & cap) != 0); 179 } 180 181 @Override 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 192 public final OGLContext getContext() { 193 return context; 194 } 195 196 private static class WGLGCDisposerRecord implements DisposerRecord { 197 private long pCfgInfo; 198 public WGLGCDisposerRecord(long pCfgInfo) { 199 this.pCfgInfo = pCfgInfo; 200 } 201 public void dispose() { 202 if (pCfgInfo != 0) { 203 OGLRenderQueue.disposeGraphicsConfig(pCfgInfo); 204 pCfgInfo = 0; 205 } 206 } 207 } 208 209 @Override 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 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 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 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 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 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 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 { 372 public WGLBufferCaps(boolean dblBuf) { 373 super(imageCaps, imageCaps, 374 dblBuf ? FlipContents.UNDEFINED : null); 375 } 376 } 377 378 @Override 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 { 388 private WGLImageCaps() { 389 super(true); 390 } 391 public boolean isTrueVolatile() { 392 return true; 393 } 394 } 395 396 @Override 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 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 435 public ContextCapabilities getContextCapabilities() { 436 return oglCaps; 437 } 438 }