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