1 /* 2 * Copyright (c) 2011, 2013, 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.Graphics; 29 import java.awt.GraphicsConfiguration; 30 import java.awt.GraphicsDevice; 31 import java.awt.GraphicsEnvironment; 32 import java.awt.Image; 33 import java.awt.Rectangle; 34 import java.awt.image.ColorModel; 35 36 import sun.java2d.SunGraphics2D; 37 import sun.java2d.SurfaceData; 38 39 import sun.lwawt.macosx.CPlatformView; 40 41 public abstract class CGLSurfaceData extends OGLSurfaceData { 42 43 protected final int scale; 44 protected final int width; 45 protected final int height; 46 protected CPlatformView pView; 47 private CGLGraphicsConfig graphicsConfig; 48 49 native void validate(int xoff, int yoff, int width, int height, boolean isOpaque); 50 51 private native void initOps(long pConfigInfo, long pPeerData, long layerPtr, 52 int xoff, int yoff, boolean isOpaque); 53 54 protected native boolean initPbuffer(long pData, long pConfigInfo, 55 boolean isOpaque, int width, int height); 56 57 protected CGLSurfaceData(CGLGraphicsConfig gc, ColorModel cm, int type, 58 int width, int height) { 59 super(gc, cm, type); 60 // TEXTURE shouldn't be scaled, it is used for managed BufferedImages. 61 scale = type == TEXTURE ? 1 : gc.getDevice().getScaleFactor(); 62 this.width = width * scale; 63 this.height = height * scale; 64 } 65 66 protected CGLSurfaceData(CPlatformView pView, CGLGraphicsConfig gc, 67 ColorModel cm, int type,int width, int height) 68 { 69 this(gc, cm, type, width, height); 70 this.pView = pView; 71 this.graphicsConfig = gc; 72 73 long pConfigInfo = gc.getNativeConfigInfo(); 74 long pPeerData = 0L; 75 boolean isOpaque = true; 76 if (pView != null) { 77 pPeerData = pView.getAWTView(); 78 isOpaque = pView.isOpaque(); 79 } 80 initOps(pConfigInfo, pPeerData, 0, 0, 0, isOpaque); 81 } 82 83 protected CGLSurfaceData(CGLLayer layer, CGLGraphicsConfig gc, 84 ColorModel cm, int type,int width, int height) 85 { 86 this(gc, cm, type, width, height); 87 this.graphicsConfig = gc; 88 89 long pConfigInfo = gc.getNativeConfigInfo(); 90 long layerPtr = 0L; 91 boolean isOpaque = true; 92 if (layer != null) { 93 layerPtr = layer.getPointer(); 94 isOpaque = layer.isOpaque(); 95 } 96 initOps(pConfigInfo, 0, layerPtr, 0, 0, isOpaque); 97 } 98 99 @Override //SurfaceData 100 public GraphicsConfiguration getDeviceConfiguration() { 101 return graphicsConfig; 102 } 103 104 /** 105 * Creates a SurfaceData object representing the primary (front) buffer of 106 * an on-screen Window. 107 */ 108 public static CGLWindowSurfaceData createData(CPlatformView pView) { 109 CGLGraphicsConfig gc = getGC(pView); 110 return new CGLWindowSurfaceData(pView, gc); 111 } 112 113 /** 114 * Creates a SurfaceData object representing the intermediate buffer 115 * between the Java2D flusher thread and the AppKit thread. 116 */ 117 public static CGLLayerSurfaceData createData(CGLLayer layer) { 118 CGLGraphicsConfig gc = getGC(layer); 119 Rectangle r = layer.getBounds(); 120 return new CGLLayerSurfaceData(layer, gc, r.width, r.height); 121 } 122 123 /** 124 * Creates a SurfaceData object representing the back buffer of a 125 * double-buffered on-screen Window. 126 */ 127 public static CGLOffScreenSurfaceData createData(CPlatformView pView, 128 Image image, int type) { 129 CGLGraphicsConfig gc = getGC(pView); 130 Rectangle r = pView.getBounds(); 131 if (type == FLIP_BACKBUFFER) { 132 return new CGLOffScreenSurfaceData(pView, gc, r.width, r.height, 133 image, gc.getColorModel(), FLIP_BACKBUFFER); 134 } else { 135 return new CGLVSyncOffScreenSurfaceData(pView, gc, r.width, 136 r.height, image, gc.getColorModel(), type); 137 } 138 } 139 140 /** 141 * Creates a SurfaceData object representing an off-screen buffer (either a 142 * Pbuffer or Texture). 143 */ 144 public static CGLOffScreenSurfaceData createData(CGLGraphicsConfig gc, 145 int width, int height, ColorModel cm, Image image, int type) { 146 return new CGLOffScreenSurfaceData(null, gc, width, height, image, cm, 147 type); 148 } 149 150 public static CGLGraphicsConfig getGC(CPlatformView pView) { 151 if (pView != null) { 152 return (CGLGraphicsConfig)pView.getGraphicsConfiguration(); 153 } else { 154 // REMIND: this should rarely (never?) happen, but what if 155 // default config is not CGL? 156 GraphicsEnvironment env = GraphicsEnvironment 157 .getLocalGraphicsEnvironment(); 158 GraphicsDevice gd = env.getDefaultScreenDevice(); 159 return (CGLGraphicsConfig) gd.getDefaultConfiguration(); 160 } 161 } 162 163 public static CGLGraphicsConfig getGC(CGLLayer layer) { 164 return (CGLGraphicsConfig)layer.getGraphicsConfiguration(); 165 } 166 167 public void validate() { 168 // Overridden in CGLWindowSurfaceData below 169 } 170 171 @Override 172 public int getDefaultScale() { 173 return scale; 174 } 175 176 @Override 177 public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, 178 int dx, int dy) { 179 final int state = sg2d.transformState; 180 if (state > SunGraphics2D.TRANSFORM_TRANSLATESCALE 181 || sg2d.compositeState >= SunGraphics2D.COMP_XOR) { 182 return false; 183 } 184 if (state <= SunGraphics2D.TRANSFORM_ANY_TRANSLATE) { 185 x += sg2d.transX; 186 y += sg2d.transY; 187 } else if (state == SunGraphics2D.TRANSFORM_TRANSLATESCALE) { 188 final double[] coords = {x, y, x + w, y + h, x + dx, y + dy}; 189 sg2d.transform.transform(coords, 0, coords, 0, 3); 190 x = (int) Math.ceil(coords[0] - 0.5); 191 y = (int) Math.ceil(coords[1] - 0.5); 192 w = ((int) Math.ceil(coords[2] - 0.5)) - x; 193 h = ((int) Math.ceil(coords[3] - 0.5)) - y; 194 dx = ((int) Math.ceil(coords[4] - 0.5)) - x; 195 dy = ((int) Math.ceil(coords[5] - 0.5)) - y; 196 } 197 oglRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); 198 return true; 199 } 200 201 protected native void clearWindow(); 202 203 public static class CGLWindowSurfaceData extends CGLSurfaceData { 204 205 public CGLWindowSurfaceData(CPlatformView pView, 206 CGLGraphicsConfig gc) { 207 super(pView, gc, gc.getColorModel(), WINDOW, 0, 0); 208 } 209 210 @Override 211 public SurfaceData getReplacement() { 212 return pView.getSurfaceData(); 213 } 214 215 @Override 216 public Rectangle getBounds() { 217 Rectangle r = pView.getBounds(); 218 return new Rectangle(0, 0, r.width, r.height); 219 } 220 221 /** 222 * Returns destination Component associated with this SurfaceData. 223 */ 224 @Override 225 public Object getDestination() { 226 return pView.getDestination(); 227 } 228 229 public void validate() { 230 OGLRenderQueue rq = OGLRenderQueue.getInstance(); 231 rq.lock(); 232 try { 233 rq.flushAndInvokeNow(new Runnable() { 234 public void run() { 235 Rectangle peerBounds = pView.getBounds(); 236 validate(0, 0, peerBounds.width, peerBounds.height, pView.isOpaque()); 237 } 238 }); 239 } finally { 240 rq.unlock(); 241 } 242 } 243 244 @Override 245 public void invalidate() { 246 super.invalidate(); 247 clearWindow(); 248 } 249 } 250 251 /** 252 * A surface which implements an intermediate buffer between 253 * the Java2D flusher thread and the AppKit thread. 254 * 255 * This surface serves as a buffer attached to a CGLLayer and 256 * the layer redirects all painting to the buffer's graphics. 257 */ 258 public static class CGLLayerSurfaceData extends CGLSurfaceData { 259 260 private CGLLayer layer; 261 262 public CGLLayerSurfaceData(CGLLayer layer, CGLGraphicsConfig gc, 263 int width, int height) { 264 super(layer, gc, gc.getColorModel(), FBOBJECT, width, height); 265 this.layer = layer; 266 initSurface(this.width, this.height); 267 } 268 269 @Override 270 public SurfaceData getReplacement() { 271 return layer.getSurfaceData(); 272 } 273 274 @Override 275 boolean isOnScreen() { 276 return true; 277 } 278 279 @Override 280 public Rectangle getBounds() { 281 return new Rectangle(width, height); 282 } 283 284 @Override 285 public Object getDestination() { 286 return layer.getDestination(); 287 } 288 289 @Override 290 public int getTransparency() { 291 return layer.getTransparency(); 292 } 293 294 @Override 295 public void invalidate() { 296 super.invalidate(); 297 clearWindow(); 298 } 299 } 300 301 /** 302 * A surface which implements a v-synced flip back-buffer with COPIED 303 * FlipContents. 304 * 305 * This surface serves as a back-buffer to the outside world, while it is 306 * actually an offscreen surface. When the BufferStrategy this surface 307 * belongs to is showed, it is first copied to the real private 308 * FLIP_BACKBUFFER, which is then flipped. 309 */ 310 public static class CGLVSyncOffScreenSurfaceData extends 311 CGLOffScreenSurfaceData { 312 private CGLOffScreenSurfaceData flipSurface; 313 314 public CGLVSyncOffScreenSurfaceData(CPlatformView pView, 315 CGLGraphicsConfig gc, int width, int height, Image image, 316 ColorModel cm, int type) { 317 super(pView, gc, width, height, image, cm, type); 318 flipSurface = CGLSurfaceData.createData(pView, image, 319 FLIP_BACKBUFFER); 320 } 321 322 public SurfaceData getFlipSurface() { 323 return flipSurface; 324 } 325 326 @Override 327 public void flush() { 328 flipSurface.flush(); 329 super.flush(); 330 } 331 } 332 333 public static class CGLOffScreenSurfaceData extends CGLSurfaceData { 334 private Image offscreenImage; 335 336 public CGLOffScreenSurfaceData(CPlatformView pView, 337 CGLGraphicsConfig gc, int width, int height, Image image, 338 ColorModel cm, int type) { 339 super(pView, gc, cm, type, width, height); 340 offscreenImage = image; 341 initSurface(this.width, this.height); 342 } 343 344 @Override 345 public SurfaceData getReplacement() { 346 return restoreContents(offscreenImage); 347 } 348 349 @Override 350 public Rectangle getBounds() { 351 if (type == FLIP_BACKBUFFER) { 352 Rectangle r = pView.getBounds(); 353 return new Rectangle(0, 0, r.width, r.height); 354 } else { 355 return new Rectangle(width, height); 356 } 357 } 358 359 /** 360 * Returns destination Image associated with this SurfaceData. 361 */ 362 @Override 363 public Object getDestination() { 364 return offscreenImage; 365 } 366 } 367 368 // Mac OS X specific APIs for JOGL/Java2D bridge... 369 370 // given a surface create and attach GL context, then return it 371 private native static long createCGLContextOnSurface(CGLSurfaceData sd, 372 long sharedContext); 373 374 public static long createOGLContextOnSurface(Graphics g, long sharedContext) { 375 SurfaceData sd = ((SunGraphics2D) g).surfaceData; 376 if ((sd instanceof CGLSurfaceData) == true) { 377 CGLSurfaceData cglsd = (CGLSurfaceData) sd; 378 return createCGLContextOnSurface(cglsd, sharedContext); 379 } else { 380 return 0L; 381 } 382 } 383 384 // returns whether or not the makeCurrent operation succeeded 385 native static boolean makeCGLContextCurrentOnSurface(CGLSurfaceData sd, 386 long ctx); 387 388 public static boolean makeOGLContextCurrentOnSurface(Graphics g, long ctx) { 389 SurfaceData sd = ((SunGraphics2D) g).surfaceData; 390 if ((ctx != 0L) && ((sd instanceof CGLSurfaceData) == true)) { 391 CGLSurfaceData cglsd = (CGLSurfaceData) sd; 392 return makeCGLContextCurrentOnSurface(cglsd, ctx); 393 } else { 394 return false; 395 } 396 } 397 398 // additional cleanup 399 private native static void destroyCGLContext(long ctx); 400 401 public static void destroyOGLContext(long ctx) { 402 if (ctx != 0L) { 403 destroyCGLContext(ctx); 404 } 405 } 406 }