1 /* 2 * Copyright (c) 2004, 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.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 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 // it is possible for the component to have size 0x0, adjust it to 327 // be at least 1x1 to avoid IAE 328 int w = Math.max(1, target.getWidth()); 329 int h = Math.max(1, target.getHeight()); 330 return new SunVolatileImage(target, 331 w, h, 332 Boolean.TRUE); 333 } 334 335 /** 336 * Performs the native WGL flip operation for the given target Component. 337 */ 338 @Override 339 public void flip(WComponentPeer peer, 340 Component target, VolatileImage backBuffer, 341 int x1, int y1, int x2, int y2, 342 BufferCapabilities.FlipContents flipAction) 343 { 344 if (flipAction == BufferCapabilities.FlipContents.COPIED) { 345 SurfaceManager vsm = SurfaceManager.getManager(backBuffer); 346 SurfaceData sd = vsm.getPrimarySurfaceData(); 347 348 if (sd instanceof WGLVSyncOffScreenSurfaceData) { 349 WGLVSyncOffScreenSurfaceData vsd = 350 (WGLVSyncOffScreenSurfaceData)sd; 351 SurfaceData bbsd = vsd.getFlipSurface(); 352 Graphics2D bbg = 353 new SunGraphics2D(bbsd, Color.black, Color.white, null); 354 try { 355 bbg.drawImage(backBuffer, 0, 0, null); 356 } finally { 357 bbg.dispose(); 358 } 359 } else { 360 Graphics g = peer.getGraphics(); 361 try { 362 g.drawImage(backBuffer, 363 x1, y1, x2, y2, 364 x1, y1, x2, y2, 365 null); 366 } finally { 367 g.dispose(); 368 } 369 return; 370 } 371 } else if (flipAction == BufferCapabilities.FlipContents.PRIOR) { 372 // not supported by WGL... 373 return; 374 } 375 376 OGLSurfaceData.swapBuffers(peer.getData()); 377 378 if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) { 379 Graphics g = backBuffer.getGraphics(); 380 try { 381 g.setColor(target.getBackground()); 382 g.fillRect(0, 0, 383 backBuffer.getWidth(), 384 backBuffer.getHeight()); 385 } finally { 386 g.dispose(); 387 } 388 } 389 } 390 391 private static class WGLBufferCaps extends BufferCapabilities { 392 public WGLBufferCaps(boolean dblBuf) { 393 super(imageCaps, imageCaps, 394 dblBuf ? FlipContents.UNDEFINED : null); 395 } 396 } 397 398 @Override 399 public BufferCapabilities getBufferCapabilities() { 400 if (bufferCaps == null) { 401 boolean dblBuf = isCapPresent(CAPS_DOUBLEBUFFERED); 402 bufferCaps = new WGLBufferCaps(dblBuf); 403 } 404 return bufferCaps; 405 } 406 407 private static class WGLImageCaps extends ImageCapabilities { 408 private WGLImageCaps() { 409 super(true); 410 } 411 public boolean isTrueVolatile() { 412 return true; 413 } 414 } 415 416 @Override 417 public ImageCapabilities getImageCapabilities() { 418 return imageCaps; 419 } 420 421 /** 422 * {@inheritDoc} 423 * 424 * @see sun.java2d.pipe.hw.AccelGraphicsConfig#createCompatibleVolatileImage 425 */ 426 @Override 427 public VolatileImage 428 createCompatibleVolatileImage(int width, int height, 429 int transparency, int type) 430 { 431 if (type == FLIP_BACKBUFFER || type == WINDOW || type == UNDEFINED || 432 transparency == Transparency.BITMASK) 433 { 434 return null; 435 } 436 437 if (type == FBOBJECT) { 438 if (!isCapPresent(CAPS_EXT_FBOBJECT)) { 439 return null; 440 } 441 } else if (type == PBUFFER) { 442 boolean isOpaque = transparency == Transparency.OPAQUE; 443 if (!isOpaque && !isCapPresent(CAPS_STORED_ALPHA)) { 444 return null; 445 } 446 } 447 448 SunVolatileImage vi = new AccelTypedVolatileImage(this, width, height, 449 transparency, type); 450 Surface sd = vi.getDestSurface(); 451 if (!(sd instanceof AccelSurface) || 452 ((AccelSurface)sd).getType() != type) 453 { 454 vi.flush(); 455 vi = null; 456 } 457 458 return vi; 459 } 460 461 /** 462 * {@inheritDoc} 463 * 464 * @see sun.java2d.pipe.hw.AccelGraphicsConfig#getContextCapabilities 465 */ 466 @Override 467 public ContextCapabilities getContextCapabilities() { 468 return oglCaps; 469 } 470 471 @Override 472 public void addDeviceEventListener(AccelDeviceEventListener l) { 473 AccelDeviceEventNotifier.addListener(l, screen.getScreen()); 474 } 475 476 @Override 477 public void removeDeviceEventListener(AccelDeviceEventListener l) { 478 AccelDeviceEventNotifier.removeListener(l); 479 } 480 }