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 getDefaultPixFmt(int screennum)77 public static native int getDefaultPixFmt(int screennum); initWGL()78 private static native boolean initWGL(); getWGLConfigInfo(int screennum, int visualnum)79 private static native long getWGLConfigInfo(int screennum, int visualnum); getOGLCapabilities(long configInfo)80 private static native int getOGLCapabilities(long configInfo); 81 82 static { 83 wglAvailable = initWGL(); 84 } 85 86 @SuppressWarnings("deprecation") WGLGraphicsConfig(Win32GraphicsDevice device, int visualnum, long configInfo, ContextCapabilities oglCaps)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 getProxyKey()102 public Object getProxyKey() { 103 return this; 104 } 105 106 @Override createManagedSurface(int w, int h, int transparency)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 getConfig(Win32GraphicsDevice device, int pixfmt)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; WGLGetConfigInfo(int screen, int pixfmt)164 private WGLGetConfigInfo(int screen, int pixfmt) { 165 this.screen = screen; 166 this.pixfmt = pixfmt; 167 } 168 @Override run()169 public void run() { 170 cfginfo = getWGLConfigInfo(screen, pixfmt); 171 } getConfigInfo()172 public long getConfigInfo() { 173 return cfginfo; 174 } 175 } 176 isWGLAvailable()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 isCapPresent(int cap)186 public final boolean isCapPresent(int cap) { 187 return ((oglCaps.getCaps() & cap) != 0); 188 } 189 190 @Override getNativeConfigInfo()191 public final long getNativeConfigInfo() { 192 return pConfigInfo; 193 } 194 195 @Override getContext()196 public final OGLContext getContext() { 197 return context; 198 } 199 200 private static class WGLGCDisposerRecord implements DisposerRecord { 201 private long pCfgInfo; WGLGCDisposerRecord(long pCfgInfo)202 public WGLGCDisposerRecord(long pCfgInfo) { 203 this.pCfgInfo = pCfgInfo; 204 } 205 @Override dispose()206 public void dispose() { 207 if (pCfgInfo != 0) { 208 OGLRenderQueue.disposeGraphicsConfig(pCfgInfo); 209 pCfgInfo = 0; 210 } 211 } 212 } 213 214 @Override displayChanged()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 getColorModel(int transparency)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 toString()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 createSurfaceData(WComponentPeer peer, int numBackBuffers)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 assertOperationSupported(Component target, int numBuffers, BufferCapabilities caps)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 createBackBuffer(WComponentPeer peer)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 flip(WComponentPeer peer, Component target, VolatileImage backBuffer, int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction)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 { WGLBufferCaps(boolean dblBuf)377 public WGLBufferCaps(boolean dblBuf) { 378 super(imageCaps, imageCaps, 379 dblBuf ? FlipContents.UNDEFINED : null); 380 } 381 } 382 383 @Override getBufferCapabilities()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 { WGLImageCaps()393 private WGLImageCaps() { 394 super(true); 395 } 396 @Override isTrueVolatile()397 public boolean isTrueVolatile() { 398 return true; 399 } 400 } 401 402 @Override getImageCapabilities()403 public ImageCapabilities getImageCapabilities() { 404 return imageCaps; 405 } 406 407 @Override 408 public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency, int type)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 getContextCapabilities()431 public ContextCapabilities getContextCapabilities() { 432 return oglCaps; 433 } 434 } 435