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