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