1 /* 2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * - Redistribution of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistribution in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * Neither the name of Sun Microsystems, Inc. or the names of 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * This software is provided "AS IS," without a warranty of any kind. ALL 20 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN 23 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR 24 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR 25 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR 26 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR 27 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE 28 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, 29 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF 30 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 31 * 32 * You acknowledge that this software is not designed or intended for use 33 * in the design, construction, operation or maintenance of any nuclear 34 * facility. 35 * 36 * Sun gratefully acknowledges that this software was originally authored 37 * and developed by Kenneth Bradley Russell and Christopher John Kline. 38 */ 39 40 package com.sun.opengl.impl; 41 42 import java.awt.Component; 43 import java.nio.*; 44 45 import javax.media.opengl.*; 46 import com.sun.gluegen.runtime.*; 47 48 public abstract class GLContextImpl extends GLContext { 49 protected GLContextLock lock = new GLContextLock(); 50 protected static final boolean DEBUG = Debug.debug("GLContextImpl"); 51 protected static final boolean VERBOSE = Debug.verbose(); 52 protected static final boolean NO_FREE = Debug.isPropertyDefined("jogl.GLContext.nofree"); 53 // NOTE: default sense of GLContext optimization disabled in JSR-231 54 // 1.0 beta 5 due to problems on X11 platforms (both Linux and 55 // Solaris) when moving and resizing windows. Apparently GLX tokens 56 // get sent to the X server under the hood (and out from under the 57 // cover of the AWT lock) in these situations. Users requiring 58 // multi-screen X11 applications can manually enable this flag. It 59 // basically had no tangible effect on the Windows or Mac OS X 60 // platforms anyway in particular with the disabling of the 61 // GLWorkerThread which we found to be necessary in 1.0 beta 4. 62 protected boolean optimizationEnabled = Debug.isPropertyDefined("jogl.GLContext.optimize"); 63 64 // Cache of the functions that are available to be called at the current 65 // moment in time 66 protected FunctionAvailabilityCache functionAvailability; 67 // Table that holds the addresses of the native C-language entry points for 68 // OpenGL functions. 69 private GLProcAddressTable glProcAddressTable; 70 71 // Tracks creation and initialization of buffer objects to avoid 72 // repeated glGet calls upon glMapBuffer operations 73 private GLBufferSizeTracker bufferSizeTracker; 74 75 // Tracks creation and deletion of server-side OpenGL objects when 76 // the Java2D/OpenGL pipeline is active and using FBOs to render 77 private GLObjectTracker tracker; 78 // Supports deletion of these objects when no other context is 79 // current which can support immediate deletion of them 80 private GLObjectTracker deletedObjectTracker; 81 82 protected GL gl; GLContextImpl(GLContext shareWith)83 public GLContextImpl(GLContext shareWith) { 84 this(shareWith, false); 85 } 86 GLContextImpl(GLContext shareWith, boolean dontShareWithJava2D)87 public GLContextImpl(GLContext shareWith, boolean dontShareWithJava2D) { 88 functionAvailability = new FunctionAvailabilityCache(this); 89 GLContext shareContext = shareWith; 90 if (!dontShareWithJava2D) { 91 shareContext = Java2D.filterShareContext(shareWith); 92 } 93 if (shareContext != null) { 94 GLContextShareSet.registerSharing(this, shareContext); 95 } 96 // Always indicate real behind-the-scenes sharing to track deleted objects 97 if (shareContext == null) { 98 shareContext = Java2D.filterShareContext(shareWith); 99 } 100 GLContextShareSet.registerForObjectTracking(shareWith, this, shareContext); 101 GLContextShareSet.registerForBufferObjectSharing(shareWith, this); 102 // This must occur after the above calls into the 103 // GLContextShareSet, which set up state needed by the GL object 104 setGL(createGL()); 105 } 106 makeCurrent()107 public int makeCurrent() throws GLException { 108 // Support calls to makeCurrent() over and over again with 109 // different contexts without releasing them 110 // Could implement this more efficiently without explicit 111 // releasing of the underlying context; would require more error 112 // checking during the makeCurrentImpl phase 113 GLContext current = getCurrent(); 114 if (current != null) { 115 if (current == this) { 116 // Assume we don't need to make this context current again 117 // For Mac OS X, however, we need to update the context to track resizes 118 update(); 119 return CONTEXT_CURRENT; 120 } else { 121 current.release(); 122 } 123 } 124 125 if (GLWorkerThread.isStarted() && 126 !GLWorkerThread.isWorkerThread()) { 127 // Kick the GLWorkerThread off its current context 128 GLWorkerThread.invokeLater(new Runnable() { public void run() {} }); 129 } 130 131 lock.lock(); 132 int res = 0; 133 try { 134 res = makeCurrentImpl(); 135 if ((tracker != null) && 136 (res == CONTEXT_CURRENT_NEW)) { 137 // Increase reference count of GLObjectTracker 138 tracker.ref(); 139 } 140 } catch (GLException e) { 141 lock.unlock(); 142 throw(e); 143 } 144 if (res == CONTEXT_NOT_CURRENT) { 145 lock.unlock(); 146 } else { 147 setCurrent(this); 148 149 // Try cleaning up any stale server-side OpenGL objects 150 // FIXME: not sure what to do here if this throws 151 if (deletedObjectTracker != null) { 152 deletedObjectTracker.clean(getGL()); 153 } 154 } 155 return res; 156 } 157 makeCurrentImpl()158 protected abstract int makeCurrentImpl() throws GLException; 159 release()160 public void release() throws GLException { 161 if (!lock.isHeld()) { 162 throw new GLException("Context not current on current thread"); 163 } 164 setCurrent(null); 165 try { 166 releaseImpl(); 167 } finally { 168 lock.unlock(); 169 } 170 } 171 releaseImpl()172 protected abstract void releaseImpl() throws GLException; 173 destroy()174 public void destroy() { 175 if (lock.isHeld()) { 176 throw new GLException("Can not destroy context while it is current"); 177 } 178 179 if (tracker != null) { 180 // Don't need to do anything for contexts that haven't been 181 // created yet 182 if (isCreated()) { 183 // If we are tracking creation and destruction of server-side 184 // OpenGL objects, we must decrement the reference count of the 185 // GLObjectTracker upon context destruction. 186 // 187 // Note that we can only eagerly delete these server-side 188 // objects if there is another context currrent right now 189 // which shares textures and display lists with this one. 190 tracker.unref(deletedObjectTracker); 191 } 192 } 193 194 // Because we don't know how many other contexts we might be 195 // sharing with (and it seems too complicated to implement the 196 // GLObjectTracker's ref/unref scheme for the buffer-related 197 // optimizations), simply clear the cache of known buffers' sizes 198 // when we destroy contexts 199 bufferSizeTracker.clearCachedBufferSizes(); 200 201 // Must hold the lock around the destroy operation to make sure we 202 // don't destroy the context out from under another thread rendering to it 203 lock.lock(); 204 try { 205 destroyImpl(); 206 } finally { 207 lock.unlock(); 208 } 209 } 210 destroyImpl()211 protected abstract void destroyImpl() throws GLException; 212 213 // This is only needed for Mac OS X on-screen contexts update()214 protected void update() throws GLException { 215 } 216 isSynchronized()217 public boolean isSynchronized() { 218 return !lock.getFailFastMode(); 219 } 220 setSynchronized(boolean isSynchronized)221 public void setSynchronized(boolean isSynchronized) { 222 lock.setFailFastMode(!isSynchronized); 223 } 224 getGL()225 public GL getGL() { 226 return gl; 227 } 228 setGL(GL gl)229 public void setGL(GL gl) { 230 this.gl = gl; 231 } 232 getPlatformGLExtensions()233 public abstract Object getPlatformGLExtensions(); 234 235 //---------------------------------------------------------------------- 236 // Helpers for various context implementations 237 // 238 239 /** Create the GL for this context. */ createGL()240 protected GL createGL() { 241 GLImpl gl = new GLImpl(this); 242 if (tracker != null) { 243 gl.setObjectTracker(tracker); 244 } 245 return gl; 246 } 247 getGLProcAddressTable()248 public GLProcAddressTable getGLProcAddressTable() { 249 if (glProcAddressTable == null) { 250 // FIXME: cache ProcAddressTables by capability bits so we can 251 // share them among contexts with the same capabilities 252 glProcAddressTable = new GLProcAddressTable(); 253 } 254 return glProcAddressTable; 255 } 256 257 /** 258 * Pbuffer support; given that this is a GLContext associated with a 259 * pbuffer, binds this pbuffer to its texture target. 260 */ bindPbufferToTexture()261 public abstract void bindPbufferToTexture(); 262 263 /** 264 * Pbuffer support; given that this is a GLContext associated with a 265 * pbuffer, releases this pbuffer from its texture target. 266 */ releasePbufferFromTexture()267 public abstract void releasePbufferFromTexture(); 268 glAllocateMemoryNV(int arg0, float arg1, float arg2, float arg3)269 public abstract ByteBuffer glAllocateMemoryNV(int arg0, float arg1, float arg2, float arg3); 270 271 /* 272 * Sets the swap interval for onscreen OpenGL contexts. Has no 273 * effect for offscreen contexts. 274 */ setSwapInterval(final int interval)275 public void setSwapInterval(final int interval) { 276 } 277 278 /** Maps the given "platform-independent" function name to a real function 279 name. Currently this is only used to map "glAllocateMemoryNV" and 280 associated routines to wglAllocateMemoryNV / glXAllocateMemoryNV. */ mapToRealGLFunctionName(String glFunctionName)281 protected abstract String mapToRealGLFunctionName(String glFunctionName); 282 283 /** Maps the given "platform-independent" extension name to a real 284 function name. Currently this is only used to map 285 "GL_ARB_pbuffer" and "GL_ARB_pixel_format" to "WGL_ARB_pbuffer" 286 and "WGL_ARB_pixel_format" (not yet mapped to X11). */ mapToRealGLExtensionName(String glExtensionName)287 protected abstract String mapToRealGLExtensionName(String glExtensionName); 288 289 /** Returns a non-null (but possibly empty) string containing the 290 space-separated list of available platform-dependent (e.g., WGL, 291 GLX) extensions. Can only be called while this context is 292 current. */ getPlatformExtensionsString()293 public abstract String getPlatformExtensionsString(); 294 295 /** Helper routine which resets a ProcAddressTable generated by the 296 GLEmitter by looking up anew all of its function pointers. */ resetProcAddressTable(Object table)297 protected void resetProcAddressTable(Object table) { 298 ProcAddressHelper.resetProcAddressTable(table, GLDrawableFactoryImpl.getFactoryImpl()); 299 } 300 301 /** Indicates whether the underlying OpenGL context has been 302 created. This is used to manage sharing of display lists and 303 textures between contexts. */ isCreated()304 public abstract boolean isCreated(); 305 306 /** 307 * Resets the cache of which GL functions are available for calling through this 308 * context. See {@link #isFunctionAvailable(String)} for more information on 309 * the definition of "available". 310 */ resetGLFunctionAvailability()311 protected void resetGLFunctionAvailability() { 312 // In order to be able to allow the user to uniformly install the 313 // debug and trace pipelines in their GLEventListener.init() 314 // method (for both GLCanvas and GLJPanel), we need to reset the 315 // actual GL object in the GLDrawable as well 316 setGL(createGL()); 317 318 functionAvailability.flush(); 319 if (DEBUG) { 320 System.err.println(getThreadName() + ": !!! Initializing OpenGL extension address table for " + this); 321 } 322 resetProcAddressTable(getGLProcAddressTable()); 323 } 324 325 /** 326 * Returns true if the specified OpenGL core- or extension-function can be 327 * successfully called using this GL context given the current host (OpenGL 328 * <i>client</i>) and display (OpenGL <i>server</i>) configuration. 329 * 330 * See {@link GL#isFunctionAvailable(String)} for more details. 331 * 332 * @param glFunctionName the name of the OpenGL function (e.g., use 333 * "glPolygonOffsetEXT" to check if the {@link 334 * javax.media.opengl.GL#glPolygonOffsetEXT(float,float)} is available). 335 */ isFunctionAvailable(String glFunctionName)336 protected boolean isFunctionAvailable(String glFunctionName) { 337 return functionAvailability.isFunctionAvailable(mapToRealGLFunctionName(glFunctionName)); 338 } 339 340 /** 341 * Returns true if the specified OpenGL extension can be 342 * successfully called using this GL context given the current host (OpenGL 343 * <i>client</i>) and display (OpenGL <i>server</i>) configuration. 344 * 345 * See {@link GL#isExtensionAvailable(String)} for more details. 346 * 347 * @param glExtensionName the name of the OpenGL extension (e.g., 348 * "GL_VERTEX_PROGRAM_ARB"). 349 */ isExtensionAvailable(String glExtensionName)350 public boolean isExtensionAvailable(String glExtensionName) { 351 return functionAvailability.isExtensionAvailable(mapToRealGLExtensionName(glExtensionName)); 352 } 353 354 /** Indicates which floating-point pbuffer implementation is in 355 use. Returns one of GLPbuffer.APPLE_FLOAT, GLPbuffer.ATI_FLOAT, 356 or GLPbuffer.NV_FLOAT. */ getFloatingPointMode()357 public int getFloatingPointMode() throws GLException { 358 throw new GLException("Not supported on non-pbuffer contexts"); 359 } 360 361 /** On some platforms the mismatch between OpenGL's coordinate 362 system (origin at bottom left) and the window system's 363 coordinate system (origin at top left) necessitates a vertical 364 flip of pixels read from offscreen contexts. */ offscreenImageNeedsVerticalFlip()365 public abstract boolean offscreenImageNeedsVerticalFlip(); 366 367 /** Only called for offscreen contexts; needed by glReadPixels */ getOffscreenContextPixelDataType()368 public abstract int getOffscreenContextPixelDataType(); 369 getThreadName()370 protected static String getThreadName() { 371 return Thread.currentThread().getName(); 372 } 373 toHexString(long hex)374 public static String toHexString(long hex) { 375 return "0x" + Long.toHexString(hex); 376 } 377 378 //---------------------------------------------------------------------- 379 // Helpers for buffer object optimizations 380 setBufferSizeTracker(GLBufferSizeTracker bufferSizeTracker)381 public void setBufferSizeTracker(GLBufferSizeTracker bufferSizeTracker) { 382 this.bufferSizeTracker = bufferSizeTracker; 383 } 384 getBufferSizeTracker()385 public GLBufferSizeTracker getBufferSizeTracker() { 386 return bufferSizeTracker; 387 } 388 389 //--------------------------------------------------------------------------- 390 // Helpers for integration with Java2D/OpenGL pipeline when FBOs are 391 // being used 392 // 393 setObjectTracker(GLObjectTracker tracker)394 public void setObjectTracker(GLObjectTracker tracker) { 395 this.tracker = tracker; 396 } 397 getObjectTracker()398 public GLObjectTracker getObjectTracker() { 399 return tracker; 400 } 401 setDeletedObjectTracker(GLObjectTracker deletedObjectTracker)402 public void setDeletedObjectTracker(GLObjectTracker deletedObjectTracker) { 403 this.deletedObjectTracker = deletedObjectTracker; 404 } 405 getDeletedObjectTracker()406 public GLObjectTracker getDeletedObjectTracker() { 407 return deletedObjectTracker; 408 } 409 410 //--------------------------------------------------------------------------- 411 // Helpers for context optimization where the last context is left 412 // current on the OpenGL worker thread 413 // 414 isOptimizable()415 public boolean isOptimizable() { 416 return optimizationEnabled; 417 } 418 hasWaiters()419 public boolean hasWaiters() { 420 return lock.hasWaiters(); 421 } 422 } 423