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