/* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN * MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ package net.java.games.jogl.impl; import java.awt.Component; import net.java.games.jogl.*; import net.java.games.gluegen.runtime.*; public abstract class GLContextImpl extends GLContext { protected GLContextLock lock = new GLContextLock(); protected static final boolean DEBUG = Debug.debug("GLContextImpl"); protected static final boolean VERBOSE = Debug.verbose(); protected static final boolean NO_FREE = Debug.isPropertyDefined("jogl.GLContext.nofree"); // Cache of the functions that are available to be called at the current // moment in time protected FunctionAvailabilityCache functionAvailability; protected GL gl; protected GLU glu = new GLUImpl(gluProcAddressTable); protected static final GLUProcAddressTable gluProcAddressTable = new GLUProcAddressTable(); protected static boolean haveResetGLUProcAddressTable; public GLContextImpl(GLContext shareWith) { setGL(createGL()); functionAvailability = new FunctionAvailabilityCache(this); if (shareWith != null) { GLContextShareSet.registerSharing(this, shareWith); } } public int makeCurrent() throws GLException { lock.lock(); int res = 0; try { res = makeCurrentImpl(); } catch (GLException e) { lock.unlock(); throw(e); } if (res == CONTEXT_NOT_CURRENT) { lock.unlock(); } else { setCurrent(this); } return res; } protected abstract int makeCurrentImpl() throws GLException; public void release() throws GLException { if (!lock.isHeld()) { throw new GLException("Context not current on current thread"); } setCurrent(null); try { releaseImpl(); } finally { lock.unlock(); } } protected abstract void releaseImpl() throws GLException; public void destroy() { if (lock.isHeld()) { throw new GLException("Can not destroy context while it is current"); } // Should we check the lock state? It should not be current on any // thread. destroyImpl(); } protected abstract void destroyImpl() throws GLException; public boolean isSynchronized() { return !lock.getFailFastMode(); } public void setSynchronized(boolean isSynchronized) { lock.setFailFastMode(!isSynchronized); } public GL getGL() { return gl; } public void setGL(GL gl) { this.gl = gl; // Also reset the GL object for the pure-Java GLU implementation ((GLUImpl) glu).setGL(gl); } public GLU getGLU() { return glu; } public void setGLU(GLU glu) { this.glu = glu; } //---------------------------------------------------------------------- // Helpers for various context implementations // /** Create the GL for this context. */ protected abstract GL createGL(); /** * Pbuffer support; indicates whether this context is capable of * creating a subordinate pbuffer context (distinct from an * "offscreen context", which is typically software-rendered on all * platforms). */ public abstract boolean canCreatePbufferContext(); /** * Pbuffer support; creates a subordinate GLDrawable for a pbuffer * associated with this context. */ public abstract GLDrawableImpl createPbufferDrawable(GLCapabilities capabilities, int initialWidth, int initialHeight); /** * Pbuffer support; given that this is a GLContext associated with a * pbuffer, binds this pbuffer to its texture target. */ public abstract void bindPbufferToTexture(); /** * Pbuffer support; given that this is a GLContext associated with a * pbuffer, releases this pbuffer from its texture target. */ public abstract void releasePbufferFromTexture(); /* * Sets the swap interval for onscreen OpenGL contexts. Has no * effect for offscreen contexts. */ public void setSwapInterval(final int interval) { } /** Maps the given "platform-independent" function name to a real function name. Currently this is only used to map "glAllocateMemoryNV" and associated routines to wglAllocateMemoryNV / glXAllocateMemoryNV. */ protected abstract String mapToRealGLFunctionName(String glFunctionName); /** Maps the given "platform-independent" extension name to a real function name. Currently this is only used to map "GL_ARB_pbuffer" and "GL_ARB_pixel_format" to "WGL_ARB_pbuffer" and "WGL_ARB_pixel_format" (not yet mapped to X11). */ protected abstract String mapToRealGLExtensionName(String glExtensionName); /** Returns a non-null (but possibly empty) string containing the space-separated list of available platform-dependent (e.g., WGL, GLX) extensions. Can only be called while this context is current. */ public abstract String getPlatformExtensionsString(); /** Helper routine which resets a ProcAddressTable generated by the GLEmitter by looking up anew all of its function pointers. */ protected void resetProcAddressTable(Object table) { Class tableClass = table.getClass(); java.lang.reflect.Field[] fields = tableClass.getDeclaredFields(); for (int i = 0; i < fields.length; ++i) { String addressFieldName = fields[i].getName(); if (!addressFieldName.startsWith(ProcAddressHelper.PROCADDRESS_VAR_PREFIX)) { // not a proc address variable continue; } int startOfMethodName = ProcAddressHelper.PROCADDRESS_VAR_PREFIX.length(); String glFuncName = addressFieldName.substring(startOfMethodName); try { java.lang.reflect.Field addressField = tableClass.getDeclaredField(addressFieldName); assert(addressField.getType() == Long.TYPE); long newProcAddress = dynamicLookupFunction(glFuncName); // set the current value of the proc address variable in the table object addressField.setLong(table, newProcAddress); if (DEBUG) { // System.err.println(glFuncName + " = 0x" + Long.toHexString(newProcAddress)); } } catch (Exception e) { throw new GLException("Cannot get GL proc address for method \"" + glFuncName + "\": Couldn't set value of field \"" + addressFieldName + "\" in class " + tableClass.getName(), e); } } } /** Dynamically looks up the given function. */ protected abstract long dynamicLookupFunction(String glFuncName); /** Indicates whether the underlying OpenGL context has been created. This is used to manage sharing of display lists and textures between contexts. */ public abstract boolean isCreated(); /** * Resets the cache of which GL functions are available for calling through this * context. See {@link #isFunctionAvailable(String)} for more information on * the definition of "available". */ protected void resetGLFunctionAvailability() { // In order to be able to allow the user to uniformly install the // debug and trace pipelines in their GLEventListener.init() // method (for both GLCanvas and GLJPanel), we need to reset the // actual GL object in the GLDrawable as well setGL(createGL()); functionAvailability.flush(); if (!haveResetGLUProcAddressTable) { if (DEBUG) { System.err.println(getThreadName() + ": !!! Initializing GLU extension address table"); } resetProcAddressTable(gluProcAddressTable); haveResetGLUProcAddressTable = true; // Only need to do this once globally } } /** * Returns true if the specified OpenGL core- or extension-function can be * successfully called using this GL context given the current host (OpenGL * client) and display (OpenGL server) configuration. * * See {@link GL#isFunctionAvailable(String)} for more details. * * @param glFunctionName the name of the OpenGL function (e.g., use * "glPolygonOffsetEXT" to check if the {@link * net.java.games.jogl.GL#glPolygonOffsetEXT(float,float)} is available). */ protected boolean isFunctionAvailable(String glFunctionName) { return functionAvailability.isFunctionAvailable(mapToRealGLFunctionName(glFunctionName)); } /** * Returns true if the specified OpenGL extension can be * successfully called using this GL context given the current host (OpenGL * client) and display (OpenGL server) configuration. * * See {@link GL#isExtensionAvailable(String)} for more details. * * @param glExtensionName the name of the OpenGL extension (e.g., * "GL_VERTEX_PROGRAM_ARB"). */ public boolean isExtensionAvailable(String glExtensionName) { return functionAvailability.isExtensionAvailable(mapToRealGLExtensionName(glExtensionName)); } /** Indicates which floating-point pbuffer implementation is in use. Returns one of GLPbuffer.APPLE_FLOAT, GLPbuffer.ATI_FLOAT, or GLPbuffer.NV_FLOAT. */ public int getFloatingPointMode() throws GLException { throw new GLException("Not supported on non-pbuffer contexts"); } /** On some platforms the mismatch between OpenGL's coordinate system (origin at bottom left) and the window system's coordinate system (origin at top left) necessitates a vertical flip of pixels read from offscreen contexts. */ public abstract boolean offscreenImageNeedsVerticalFlip(); /** Only called for offscreen contexts; needed by glReadPixels */ public abstract int getOffscreenContextPixelDataType(); protected static String getThreadName() { return Thread.currentThread().getName(); } public static String toHexString(long hex) { return "0x" + Long.toHexString(hex); } }