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