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