diff options
Diffstat (limited to 'src/net/java/games/jogl/impl/x11/X11GLContext.java')
-rw-r--r-- | src/net/java/games/jogl/impl/x11/X11GLContext.java | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/src/net/java/games/jogl/impl/x11/X11GLContext.java b/src/net/java/games/jogl/impl/x11/X11GLContext.java new file mode 100644 index 000000000..8e9804578 --- /dev/null +++ b/src/net/java/games/jogl/impl/x11/X11GLContext.java @@ -0,0 +1,414 @@ +/* + * 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.x11; + +import java.awt.Component; +import java.util.*; +import net.java.games.gluegen.opengl.*; // for PROCADDRESS_VAR_PREFIX +import net.java.games.jogl.*; +import net.java.games.jogl.impl.*; + +public abstract class X11GLContext extends GLContext { + private static JAWT jawt; + protected long display; + protected long drawable; + protected long context; + private boolean glXQueryExtensionsStringInitialized; + private boolean glXQueryExtensionsStringAvailable; + private static final Map/*<String, String>*/ functionNameMap; + + static { + functionNameMap = new HashMap(); + functionNameMap.put("glAllocateMemoryNV", "glXAllocateMemoryNV"); + functionNameMap.put("glFreeMemoryNV", "glXFreeMemoryNV"); + } + + public X11GLContext(Component component, GLCapabilities capabilities, GLCapabilitiesChooser chooser) { + super(component, capabilities, chooser); + } + + protected GL createGL() + { + return new X11GLImpl(this); + } + + protected String mapToRealGLFunctionName(String glFunctionName) { + String lookup = (String) functionNameMap.get(glFunctionName); + if (lookup != null) { + return lookup; + } + return glFunctionName; + } + + protected String mapToRealGLExtensionName(String glExtensionName) { + return glExtensionName; + } + + protected abstract boolean isOffscreen(); + + public abstract int getOffscreenContextBufferedImageType(); + + public abstract int getOffscreenContextReadBuffer(); + + public abstract boolean offscreenImageNeedsVerticalFlip(); + + public synchronized void setRenderingThread(Thread currentThreadOrNull, Runnable initAction) { + this.willSetRenderingThread = false; + // FIXME: the JAWT on X11 grabs the AWT lock while the + // DrawingSurface is locked, which means that no other events can + // be processed. Currently we handle this by preventing the + // effects of setRenderingThread. We should figure out a better + // solution that is reasonably robust. Must file a bug to be fixed + // in the 1.5 JAWT. + } + + /** + * Creates and initializes an appropriate OpenGl context. Should only be + * called by {@link makeCurrent(Runnable)}. + */ + protected abstract void create(); + + protected synchronized boolean makeCurrent(Runnable initAction) throws GLException { + boolean created = false; + if (context == 0) { + create(); + if (DEBUG) { + System.err.println("!!! Created GL context for " + getClass().getName()); + } + created = true; + } + if (drawable == 0) { + throw new GLException("Unable to make context current; drawable was null"); + } + + // FIXME: this cast to int would be wrong on 64-bit platforms + // where the argument type to glXMakeCurrent would change (should + // probably make GLXDrawable, and maybe XID, Opaque as long) + if (!GLX.glXMakeCurrent(display, (int) drawable, context)) { + throw new GLException("Error making context current"); + } + + if (created) { + resetGLFunctionAvailability(); + initAction.run(); + } + return true; + } + + protected synchronized void free() throws GLException { + if (!GLX.glXMakeCurrent(display, 0, 0)) { + throw new GLException("Error freeing OpenGL context"); + } + } + + protected abstract void swapBuffers() throws GLException; + + + protected void resetGLFunctionAvailability() { + super.resetGLFunctionAvailability(); + resetGLProcAddressTable(); + } + + protected void resetGLProcAddressTable() { + + if (DEBUG) { + System.err.println("!!! Initializing OpenGL extension address table"); + } + + net.java.games.jogl.impl.ProcAddressTable table = getGLProcAddressTable(); + + // if GL is no longer an interface, we'll have to re-implement the code + // below so it only iterates through gl methods (a non-interface might + // have constructors, custom methods, etc). For now we assume all methods + // will be gl methods. + GL gl = getGL(); + + 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(GLEmitter.PROCADDRESS_VAR_PREFIX)) + { + // not a proc address variable + continue; + } + int startOfMethodName = GLEmitter.PROCADDRESS_VAR_PREFIX.length(); + String glFuncName = addressFieldName.substring(startOfMethodName); + try + { + java.lang.reflect.Field addressField = tableClass.getDeclaredField(addressFieldName); + assert(addressField.getType() == Long.TYPE); + // get the current value of the proc address variable in the table object + long oldProcAddress = addressField.getLong(table); + long newProcAddress = GLX.glXGetProcAddressARB(glFuncName); + /* + System.err.println( + "!!! Address=" + (newProcAddress == 0 + ? "<NULL> " + : ("0x" + + Long.toHexString(newProcAddress))) + + "\tGL func: " + glFuncName); + */ + // set the current value of the proc address variable in the table object + addressField.setLong(gl, newProcAddress); + } catch (Exception e) { + throw new GLException( + "Cannot get GL proc address for method \"" + + glFuncName + "\": Couldn't get value of field \"" + addressFieldName + + "\" in class " + tableClass.getName(), e); + } + } + + } + + public net.java.games.jogl.impl.ProcAddressTable getGLProcAddressTable() { + if (glProcAddressTable == null) { + // FIXME: cache ProcAddressTables by capability bits so we can + // share them among contexts with the same capabilities + glProcAddressTable = + new net.java.games.jogl.impl.ProcAddressTable(); + } + return glProcAddressTable; + } + + public synchronized String getPlatformExtensionsString() { + if (display == 0) { + throw new GLException("Context not current"); + } + if (!glXQueryExtensionsStringInitialized) { + glXQueryExtensionsStringAvailable = (GLX.glXGetProcAddressARB("glXQueryExtensionsString") != 0); + glXQueryExtensionsStringInitialized = true; + } + if (glXQueryExtensionsStringAvailable) { + return GLX.glXQueryExtensionsString(display, GLX.DefaultScreen(display)); + } else { + return ""; + } + } + + protected boolean isFunctionAvailable(String glFunctionName) + { + boolean available = super.isFunctionAvailable(glFunctionName); + + // Sanity check for implementations that use proc addresses for run-time + // linking: if the function IS available, then make sure there's a proc + // address for it if it's an extension or not part of the OpenGL 1.1 core + // (post GL 1.1 functions are run-time linked on windows). + assert(!available || + (getGLProcAddressTable().getAddressFor(mapToRealGLFunctionName(glFunctionName)) != 0 || + FunctionAvailabilityCache.isPartOfGLCore("1.1", mapToRealGLFunctionName(glFunctionName))) + ); + + return available; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + // Table that holds the addresses of the native C-language entry points for + // OpenGL functions. + private net.java.games.jogl.impl.ProcAddressTable glProcAddressTable; + + protected JAWT getJAWT() { + if (jawt == null) { + JAWT j = new JAWT(); + j.version(JAWTFactory.JAWT_VERSION_1_4); + if (!JAWTFactory.JAWT_GetAWT(j)) { + throw new RuntimeException("Unable to initialize JAWT"); + } + jawt = j; + } + return jawt; + } + + protected XVisualInfo chooseVisual() { + int screen = 0; // FIXME: provide way to specify this? + XVisualInfo vis = null; + if (chooser == null) { + // Note: this code path isn't taken any more now that the + // DefaultGLCapabilitiesChooser is present. However, it is being + // left in place for debugging purposes. + int[] attribs = glCapabilities2AttribList(capabilities); + vis = GLX.glXChooseVisual(display, screen, attribs); + if (vis == null) { + throw new GLException("Unable to find matching visual"); + } + if (DEBUG) { + System.err.println("Chosen visual from glXChooseVisual:"); + System.err.println(xvi2GLCapabilities(vis)); + } + } else { + int[] count = new int[1]; + XVisualInfo template = new XVisualInfo(); + template.screen(screen); + XVisualInfo[] infos = GLX.XGetVisualInfo(display, GLX.VisualScreenMask, template, count); + if (infos == null) { + throw new GLException("Error while enumerating available XVisualInfos"); + } + GLCapabilities[] caps = new GLCapabilities[infos.length]; + for (int i = 0; i < infos.length; i++) { + caps[i] = xvi2GLCapabilities(infos[i]); + } + int chosen = chooser.chooseCapabilities(capabilities, caps); + if (chosen < 0 || chosen >= caps.length) { + throw new GLException("GLCapabilitiesChooser specified invalid index (expected 0.." + (caps.length - 1) + ")"); + } + if (DEBUG) { + System.err.println("Chosen visual (" + chosen + "):"); + System.err.println(caps[chosen]); + } + vis = infos[chosen]; + if (vis == null) { + throw new GLException("GLCapabilitiesChooser chose an invalid visual"); + } + } + return vis; + } + + protected long createContext(XVisualInfo vis, boolean onscreen) { + // FIXME: support sharing of display lists between contexts + return GLX.glXCreateContext(display, vis, 0, onscreen); + } + + // Helper routine for the overridden create() to call + protected void chooseVisualAndCreateContext(boolean onscreen) { + XVisualInfo vis = chooseVisual(); + // FIXME: support sharing of display lists between contexts + context = createContext(vis, onscreen); + if (context == 0) { + throw new GLException("Unable to create OpenGL context"); + } + } + + protected int[] glCapabilities2AttribList(GLCapabilities caps) { + int colorDepth = (caps.getRedBits() + + caps.getGreenBits() + + caps.getBlueBits()); + if (colorDepth < 15) { + throw new GLException("Bit depths < 15 (i.e., non-true-color) not supported"); + } + int[] res = new int[22]; + int idx = 0; + res[idx++] = GLX.GLX_RGBA; + if (caps.getDoubleBuffered()) { + res[idx++] = GLX.GLX_DOUBLEBUFFER; + } + if (caps.getStereo()) { + res[idx++] = GLX.GLX_STEREO; + } + res[idx++] = GLX.GLX_RED_SIZE; + res[idx++] = caps.getRedBits(); + res[idx++] = GLX.GLX_GREEN_SIZE; + res[idx++] = caps.getGreenBits(); + res[idx++] = GLX.GLX_BLUE_SIZE; + res[idx++] = caps.getBlueBits(); + res[idx++] = GLX.GLX_ALPHA_SIZE; + res[idx++] = caps.getAlphaBits(); + res[idx++] = GLX.GLX_DEPTH_SIZE; + res[idx++] = caps.getDepthBits(); + res[idx++] = GLX.GLX_STENCIL_SIZE; + res[idx++] = caps.getStencilBits(); + res[idx++] = GLX.GLX_ACCUM_RED_SIZE; + res[idx++] = caps.getAccumRedBits(); + res[idx++] = GLX.GLX_ACCUM_GREEN_SIZE; + res[idx++] = caps.getAccumGreenBits(); + res[idx++] = GLX.GLX_ACCUM_BLUE_SIZE; + res[idx++] = caps.getAccumBlueBits(); + res[idx++] = 0; + return res; + } + + protected GLCapabilities xvi2GLCapabilities(XVisualInfo info) { + int[] tmp = new int[1]; + int val = glXGetConfig(info, GLX.GLX_USE_GL, tmp); + if (val == 0) { + // Visual does not support OpenGL + return null; + } + val = glXGetConfig(info, GLX.GLX_RGBA, tmp); + if (val == 0) { + // Visual does not support RGBA + return null; + } + GLCapabilities res = new GLCapabilities(); + res.setDoubleBuffered(glXGetConfig(info, GLX.GLX_DOUBLEBUFFER, tmp) != 0); + res.setStereo (glXGetConfig(info, GLX.GLX_STEREO, tmp) != 0); + // Note: use of hardware acceleration is determined by + // glXCreateContext, not by the XVisualInfo. Optimistically claim + // that all GLCapabilities have the capability to be hardware + // accelerated. + res.setHardwareAccelerated(true); + res.setDepthBits (glXGetConfig(info, GLX.GLX_DEPTH_SIZE, tmp)); + res.setStencilBits (glXGetConfig(info, GLX.GLX_STENCIL_SIZE, tmp)); + res.setRedBits (glXGetConfig(info, GLX.GLX_RED_SIZE, tmp)); + res.setGreenBits (glXGetConfig(info, GLX.GLX_GREEN_SIZE, tmp)); + res.setBlueBits (glXGetConfig(info, GLX.GLX_BLUE_SIZE, tmp)); + res.setAlphaBits (glXGetConfig(info, GLX.GLX_ALPHA_SIZE, tmp)); + res.setAccumRedBits (glXGetConfig(info, GLX.GLX_ACCUM_RED_SIZE, tmp)); + res.setAccumGreenBits(glXGetConfig(info, GLX.GLX_ACCUM_GREEN_SIZE, tmp)); + res.setAccumBlueBits (glXGetConfig(info, GLX.GLX_ACCUM_BLUE_SIZE, tmp)); + res.setAccumAlphaBits(glXGetConfig(info, GLX.GLX_ACCUM_ALPHA_SIZE, tmp)); + return res; + } + + protected String glXGetConfigErrorCode(int err) { + switch (err) { + case GLX.GLX_NO_EXTENSION: return "GLX_NO_EXTENSION"; + case GLX.GLX_BAD_SCREEN: return "GLX_BAD_SCREEN"; + case GLX.GLX_BAD_ATTRIBUTE: return "GLX_BAD_ATTRIBUTE"; + case GLX.GLX_BAD_VISUAL: return "GLX_BAD_VISUAL"; + default: return "Unknown error code " + err; + } + } + + protected int glXGetConfig(XVisualInfo info, int attrib, int[] tmp) { + if (display == 0) { + throw new GLException("No display connection"); + } + int res = GLX.glXGetConfig(display, info, attrib, tmp); + if (res != 0) { + throw new GLException("glXGetConfig failed: error code " + glXGetConfigErrorCode(res)); + } + return tmp[0]; + } +} |