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