1 /*
   2  * Copyright (c) 2011, 2019, 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.metal;
  27 
  28 import sun.java2d.SunGraphics2D;
  29 import sun.java2d.SurfaceData;
  30 import sun.java2d.pipe.Region;
  31 
  32 import java.awt.*;
  33 
  34 /**
  35  * This class contains a number of static utility methods that may be
  36  * called (via reflection) by a third-party library in order
  37  * to interoperate with the metal-based Java 2D pipeline.
  38  *
  39  */
  40 class MTLUtilities {
  41 
  42     /**
  43      * These OGL-specific surface type constants are the same as those
  44      * defined in the MTLSurfaceDataBase class and are duplicated here so that
  45      * clients of this API can access them more easily via reflection.
  46      */
  47     public static final int UNDEFINED       = MTLSurfaceDataBase.UNDEFINED;
  48     public static final int WINDOW          = MTLSurfaceDataBase.WINDOW;
  49     public static final int TEXTURE         = MTLSurfaceDataBase.TEXTURE;
  50     public static final int FLIP_BACKBUFFER = MTLSurfaceDataBase.FLIP_BACKBUFFER;
  51     public static final int FBOBJECT        = MTLSurfaceDataBase.FBOBJECT;
  52 
  53     private MTLUtilities() {
  54     }
  55 
  56     /**
  57      * Returns true if the current thread is the OGL QueueFlusher thread.
  58      */
  59     public static boolean isQueueFlusherThread() {
  60         return MTLRenderQueue.isQueueFlusherThread();
  61     }
  62 
  63     /**
  64      * Invokes the given Runnable on the MTL QueueFlusher thread with the
  65      * MTL context corresponding to the given Graphics object made
  66      * current.  It is legal for MTL code executed in the given
  67      * Runnable to change the current MTL context; it will be reset
  68      * once the Runnable completes.  No guarantees are made as to the
  69      * state of the MTL context of the Graphics object; for
  70      *
  71      * In order to avoid deadlock, it is important that the given Runnable
  72      * does not attempt to acquire the AWT lock, as that will be handled
  73      * automatically as part of the {@code rq.flushAndInvokeNow()} step.
  74      *
  75      * @param g the Graphics object for the corresponding destination surface;
  76      * if null, the step making a context current to the destination surface
  77      * will be skipped
  78      * @param r the action to be performed on the QFT; cannot be null
  79      * @return true if the operation completed successfully, or false if
  80      * there was any problem making a context current to the surface
  81      * associated with the given Graphics object
  82      */
  83     public static boolean invokeWithMTLContextCurrent(Graphics g, Runnable r) {
  84         MTLRenderQueue rq = MTLRenderQueue.getInstance();
  85         rq.lock();
  86         try {
  87             if (g != null) {
  88                 if (!(g instanceof SunGraphics2D)) {
  89                     return false;
  90                 }
  91                 SurfaceData sData = ((SunGraphics2D)g).surfaceData;
  92                 if (!(sData instanceof MTLSurfaceDataBase)) {
  93                     return false;
  94                 }
  95 
  96                 // make a context current to the destination surface
  97                 MTLContext.validateContext((MTLSurfaceDataBase)sData);
  98             }
  99 
 100             // invoke the given runnable on the QFT
 101             rq.flushAndInvokeNow(r);
 102 
 103             // invalidate the current context so that the next time we render
 104             // with Java 2D, the context state will be completely revalidated
 105             MTLContext.invalidateCurrentContext();
 106         } finally {
 107             rq.unlock();
 108         }
 109 
 110         return true;
 111     }
 112 
 113     /**
 114      * Invokes the given Runnable on the MTL QueueFlusher thread with the
 115      * "shared" MTL context (corresponding to the given
 116      * GraphicsConfiguration object) made current.  This method is typically
 117      * used when the Runnable needs a current context to complete its
 118      * operation, but does not require that the context be made current to
 119      * a particular surface.  For example, an application may call this
 120      * method so that the given Runnable can query the OpenGL capabilities
 121      * of the given GraphicsConfiguration, without making a context current
 122      * to a dummy surface (or similar hacky techniques).
 123      *
 124      * In order to avoid deadlock, it is important that the given Runnable
 125      * does not attempt to acquire the AWT lock, as that will be handled
 126      * automatically as part of the {@code rq.flushAndInvokeNow()} step.
 127      *
 128      * @param config the GraphicsConfiguration object whose "shared"
 129      * context will be made current during this operation; if this value is
 130      * null or if MTL is not enabled for the GraphicsConfiguration, this
 131      * method will return false
 132      * @param r the action to be performed on the QFT; cannot be null
 133      * @return true if the operation completed successfully, or false if
 134      * there was any problem making the shared context current
 135      */
 136     public static boolean
 137     invokeWithMTLSharedContextCurrent(GraphicsConfiguration config,
 138                                       Runnable r)
 139     {
 140         if (!(config instanceof MTLGraphicsConfigBase)) {
 141             return false;
 142         }
 143 
 144         MTLRenderQueue rq = MTLRenderQueue.getInstance();
 145         rq.lock();
 146         try {
 147             // make the "shared" context current for the given GraphicsConfig
 148             MTLContext.setScratchSurface((MTLGraphicsConfigBase)config);
 149 
 150             // invoke the given runnable on the QFT
 151             rq.flushAndInvokeNow(r);
 152 
 153             // invalidate the current context so that the next time we render
 154             // with Java 2D, the context state will be completely revalidated
 155             MTLContext.invalidateCurrentContext();
 156         } finally {
 157             rq.unlock();
 158         }
 159 
 160         return true;
 161     }
 162 
 163     /**
 164      * Returns the Rectangle describing the MTL viewport on the
 165      * Java 2D surface associated with the given Graphics object and
 166      * component width and height. When a third-party library is
 167      * performing MTL rendering directly into the visible region of
 168      * the associated surface, this viewport helps the application
 169      * position the MTL output correctly on that surface.
 170      *
 171      * Note that the x/y values in the returned Rectangle object represent
 172      * the lower-left corner of the viewport region, relative to the
 173      * lower-left corner of the given surface.
 174      *
 175      * @param g the Graphics object for the corresponding destination surface;
 176      * cannot be null
 177      * @param componentWidth width of the component to be painted
 178      * @param componentHeight height of the component to be painted
 179      * @return a Rectangle describing the MTL viewport for the given
 180      * destination surface and component dimensions, or null if the given
 181      * Graphics object is invalid
 182      */
 183     public static Rectangle getMTLViewport(Graphics g,
 184                                            int componentWidth,
 185                                            int componentHeight)
 186     {
 187         if (!(g instanceof SunGraphics2D)) {
 188             return null;
 189         }
 190 
 191         SunGraphics2D sg2d = (SunGraphics2D)g;
 192         SurfaceData sData = sg2d.surfaceData;
 193 
 194         // this is the upper-left origin of the region to be painted,
 195         // relative to the upper-left origin of the surface
 196         // (in Java2D coordinates)
 197         int x0 = sg2d.transX;
 198         int y0 = sg2d.transY;
 199 
 200         // this is the lower-left origin of the region to be painted,
 201         // relative to the lower-left origin of the surface
 202         // (in OpenGL coordinates)
 203         Rectangle surfaceBounds = sData.getBounds();
 204         int x1 = x0;
 205         int y1 = surfaceBounds.height - (y0 + componentHeight);
 206 
 207         return new Rectangle(x1, y1, componentWidth, componentHeight);
 208     }
 209 
 210     /**
 211      * Returns the Rectangle describing the MTL scissor box on the
 212      * Java 2D surface associated with the given Graphics object.  When a
 213      * third-party library is performing MTL rendering directly
 214      * into the visible region of the associated surface, this scissor box
 215      * must be set to avoid drawing over existing rendering results.
 216      *
 217      * Note that the x/y values in the returned Rectangle object represent
 218      * the lower-left corner of the scissor region, relative to the
 219      * lower-left corner of the given surface.
 220      *
 221      * @param g the Graphics object for the corresponding destination surface;
 222      * cannot be null
 223      * @return a Rectangle describing the MTL scissor box for the given
 224      * Graphics object and corresponding destination surface, or null if the
 225      * given Graphics object is invalid or the clip region is non-rectangular
 226      */
 227     public static Rectangle getOGLScissorBox(Graphics g) {
 228         if (!(g instanceof SunGraphics2D)) {
 229             return null;
 230         }
 231 
 232         SunGraphics2D sg2d = (SunGraphics2D)g;
 233         SurfaceData sData = sg2d.surfaceData;
 234         Region r = sg2d.getCompClip();
 235         if (!r.isRectangular()) {
 236             // caller probably doesn't know how to handle shape clip
 237             // appropriately, so just return null (Swing currently never
 238             // sets a shape clip, but that could change in the future)
 239             return null;
 240         }
 241 
 242         // this is the upper-left origin of the scissor box relative to the
 243         // upper-left origin of the surface (in Java 2D coordinates)
 244         int x0 = r.getLoX();
 245         int y0 = r.getLoY();
 246 
 247         // this is the width and height of the scissor region
 248         int w = r.getWidth();
 249         int h = r.getHeight();
 250 
 251         // this is the lower-left origin of the scissor box relative to the
 252         // lower-left origin of the surface (in OpenGL coordinates)
 253         Rectangle surfaceBounds = sData.getBounds();
 254         int x1 = x0;
 255         int y1 = surfaceBounds.height - (y0 + h);
 256 
 257         return new Rectangle(x1, y1, w, h);
 258     }
 259 
 260     /**
 261      * Returns an Object identifier for the Java 2D surface associated with
 262      * the given Graphics object.  This identifier may be used to determine
 263      * whether the surface has changed since the last invocation of this
 264      * operation, and thereby whether the MTL state corresponding to the
 265      * old surface must be destroyed and recreated.
 266      *
 267      * @param g the Graphics object for the corresponding destination surface;
 268      * cannot be null
 269      * @return an identifier for the surface associated with the given
 270      * Graphics object, or null if the given Graphics object is invalid
 271      */
 272     public static Object getMTLSurfaceIdentifier(Graphics g) {
 273         if (!(g instanceof SunGraphics2D)) {
 274             return null;
 275         }
 276         return ((SunGraphics2D)g).surfaceData;
 277     }
 278 
 279     /**
 280      * Returns one of the MTL-specific surface type constants (defined in
 281      * this class), which describes the surface associated with the given
 282      * Graphics object.
 283      *
 284      * @param g the Graphics object for the corresponding destination surface;
 285      * cannot be null
 286      * @return a constant that describes the surface associated with the
 287      * given Graphics object; if the given Graphics object is invalid (i.e.
 288      * is not associated with an OpenGL surface) this method will return
 289      * {@code MTLUtilities.UNDEFINED}
 290      */
 291     public static int getMTLSurfaceType(Graphics g) {
 292         if (!(g instanceof SunGraphics2D)) {
 293             return UNDEFINED;
 294         }
 295         SurfaceData sData = ((SunGraphics2D)g).surfaceData;
 296         if (!(sData instanceof MTLSurfaceDataBase)) {
 297             return UNDEFINED;
 298         }
 299         return ((MTLSurfaceDataBase)sData).getType();
 300     }
 301 
 302     /**
 303      * Returns the MTL texture target constant (either GL_TEXTURE_2D
 304      * or GL_TEXTURE_RECTANGLE_ARB) for the surface associated with the
 305      * given Graphics object.  This method is only useful for those surface
 306      * types that are backed by an MTL texture, namely {@code TEXTURE},
 307      * {@code FBOBJECT}, and (on Windows only) {@code PBUFFER}.
 308      *
 309      * @param g the Graphics object for the corresponding destination surface;
 310      * cannot be null
 311      * @return the texture target constant for the surface associated with the
 312      * given Graphics object; if the given Graphics object is invalid (i.e.
 313      * is not associated with an MTL surface), or the associated surface
 314      * is not backed by an OpenGL texture, this method will return zero.
 315      */
 316     public static int getMTLTextureType(Graphics g) {
 317         if (!(g instanceof SunGraphics2D)) {
 318             return 0;
 319         }
 320         SurfaceData sData = ((SunGraphics2D)g).surfaceData;
 321         if (!(sData instanceof MTLSurfaceDataBase)) {
 322             return 0;
 323         }
 324         return ((MTLSurfaceDataBase)sData).getTextureTarget();
 325     }
 326 }