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