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.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 }