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 }