aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/games/jogl/impl/x11/X11GLContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/java/games/jogl/impl/x11/X11GLContext.java')
-rw-r--r--src/net/java/games/jogl/impl/x11/X11GLContext.java414
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];
+ }
+}