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