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