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