Added support for OpenGL 3.0 functionality

Added support for OpenGL 3.0 context creation (MAJOR/MINOR versions, DEBUG mode, FORWARD_COMBATIBLE mode)
Added support for OpenGL 3.0 context sharing
Added support for OpenGL 3.0 extension detection
Improved support for floating point PixelFormats (ARB_color_buffer_float)
Added support for packed floating point PixelFormats (EXT_packed_float)
Added support for sRGB PixelFormats (ARB_framebuffer_sRGB)
Added support for pseudo-FORWARD_COMBATIBLE mode (deprecated functions not loaded)
Added support for EXT_direct_state_access
This commit is contained in:
Ioannis Tsakpinis 2008-08-19 16:46:03 +00:00
parent 0deaed34a5
commit d7ee23f9b2
73 changed files with 4235 additions and 817 deletions

View file

@ -31,38 +31,35 @@
*/
package org.lwjgl.opengl;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.WeakHashMap;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.Sys;
import java.lang.reflect.Method;
import java.nio.IntBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.*;
/**
* <p/>
* Manages GL contexts. Before any rendering is done by a LWJGL system, a call should be made to GLContext.useContext() with a
* context. This will ensure that GLContext has an accurate reflection of the current context's capabilities and function
* pointers.
*
* <p/>
* This class is thread-safe in the sense that multiple threads can safely call all public methods. The class is also
* thread-aware in the sense that it tracks a per-thread current context (including capabilities and function pointers).
* That way, multiple threads can have multiple contexts current and render to them concurrently.
*
* @author elias_naur <elias_naur@users.sourceforge.net>
* @version $Revision$
* $Id$
* $Id$
*/
public final class GLContext {
/**
* Maps threads to their current context's ContextCapabilities, if any
*/
/** Maps threads to their current context's ContextCapabilities, if any */
private final static ThreadLocal current_capabilities = new ThreadLocal();
/**
@ -71,18 +68,18 @@ public final class GLContext {
* for the function pointers of gl functions. However, the 'current_capabilities' ThreadLocal
* is (relatively) expensive to look up, and since most OpenGL applications use are single threaded
* rendering, the following two is an optimization for this case.
*
* <p/>
* ThreadLocals can be thought of as a mapping between threads and values, so the idea
* is to use a lock-less cache of mappings between threads and the current ContextCapabilities. The cache
* could be any size, but in our case, we want a single sized cache for optimal performance
* in the single threaded case.
*
* <p/>
* 'fast_path_cache' is the most recent ContextCapabilities (potentially null) and its owner. By
* recent I mean the last thread setting the value in setCapabilities(). When getCapabilities()
* is called, a check to see if the current is the owner of the ContextCapabilities instance in
* fast_path_cache. If so, the instance is returned, if not, some thread has since taken ownership
* of the cache entry and the slower current_capabilities ThreadLocal is queried instead.
*
* <p/>
* No locks are needed in get/setCapabilities, because even though fast_path_cache can be accessed
* from multiple threads at once, we are guaranteed by the JVM spec that its value is always valid.
* Furthermore, if the ownership test in getCapabilities() succeeds, the cache entry can only contain
@ -120,7 +117,7 @@ public final class GLContext {
public static ContextCapabilities getCapabilities() {
CapabilitiesCacheEntry recent_cache_entry = fast_path_cache;
// Check owner of cache entry
if (recent_cache_entry.owner == Thread.currentThread()) {
if ( recent_cache_entry.owner == Thread.currentThread() ) {
/* The owner ship test succeeded, so the cache must contain the current ContextCapabilities instance
* assert recent_cache_entry.capabilities == getThreadLocalCapabilities();
*/
@ -143,7 +140,7 @@ public final class GLContext {
current_capabilities.set(capabilities);
CapabilitiesCacheEntry thread_cache_entry = (CapabilitiesCacheEntry)thread_cache_entries.get();
if (thread_cache_entry == null) {
if ( thread_cache_entry == null ) {
thread_cache_entry = new CapabilitiesCacheEntry();
thread_cache_entries.set(thread_cache_entry);
}
@ -163,8 +160,8 @@ public final class GLContext {
return System.getProperty("os.name");
}
});
for (int i = 0; i < os_prefixes.length; i++)
if (os_name.startsWith(os_prefixes[i])) {
for ( int i = 0; i < os_prefixes.length; i++ )
if ( os_name.startsWith(os_prefixes[i]) ) {
String platform_function_name = function.replaceFirst(function_prefix, os_function_prefixes[i]);
long address = getFunctionAddress(platform_function_name);
return address;
@ -172,9 +169,7 @@ public final class GLContext {
return 0;
}
/**
* Helper method to get a pointer to a named function in the OpenGL library
*/
/** Helper method to get a pointer to a named function in the OpenGL library */
static native long getFunctionAddress(String name);
/**
@ -183,21 +178,17 @@ public final class GLContext {
* @return A Set containing all available extension strings.
*/
static Set getSupportedExtensions() {
Set supported_extensions = new HashSet();
String extensions_string = GL11.glGetString(GL11.GL_EXTENSIONS);
if (extensions_string == null)
throw new IllegalStateException("glGetString(GL_EXTENSIONS) returned null - is there a context current?");
StringTokenizer tokenizer = new StringTokenizer(extensions_string);
while ( tokenizer.hasMoreTokens() ) {
String extension_string = tokenizer.nextToken();
supported_extensions.add(extension_string);
}
String version = GL11.glGetString(GL11.GL_VERSION);
if (version == null)
final Set supported_extensions = new HashSet();
// Detect OpenGL version first
final String version = GL11.glGetString(GL11.GL_VERSION);
if ( version == null )
throw new IllegalStateException("glGetString(GL_VERSION) returned null - possibly caused by missing current context.");
StringTokenizer version_tokenizer = new StringTokenizer(version, ". ");
String major_string = version_tokenizer.nextToken();
String minor_string = version_tokenizer.nextToken();
final StringTokenizer version_tokenizer = new StringTokenizer(version, ". ");
final String major_string = version_tokenizer.nextToken();
final String minor_string = version_tokenizer.nextToken();
int majorVersion = 0;
int minorVersion = 0;
@ -208,39 +199,47 @@ public final class GLContext {
LWJGLUtil.log("The major and/or minor OpenGL version is malformed: " + e.getMessage());
}
if (majorVersion >= 2) {
// ----------------------[ 2.X ]----------------------
switch (minorVersion) {
case 1:
supported_extensions.add("OpenGL21");
// Intentional fall through
case 0:
supported_extensions.add("OpenGL20");
}
// ----------------------[ 1.X ]----------------------
supported_extensions.add("OpenGL11");
supported_extensions.add("OpenGL12");
supported_extensions.add("OpenGL13");
supported_extensions.add("OpenGL14");
// ----------------------[ 3.X ]----------------------
if ( 3 <= majorVersion )
supported_extensions.add("OpenGL30");
// ----------------------[ 2.X ]----------------------
if ( 2 < majorVersion || (2 == majorVersion && 1 <= minorVersion) )
supported_extensions.add("OpenGL21");
if ( 2 <= majorVersion )
supported_extensions.add("OpenGL20");
// ----------------------[ 1.X ]----------------------
if ( 1 < majorVersion || 5 <= minorVersion )
supported_extensions.add("OpenGL15");
} else if (majorVersion == 1) {
switch (minorVersion) {
case 5:
supported_extensions.add("OpenGL15");
// Intentional fall through
case 4:
supported_extensions.add("OpenGL14");
// Intentional fall through
case 3:
supported_extensions.add("OpenGL13");
// Intentional fall through
case 2:
supported_extensions.add("OpenGL12");
// Intentional fall through
case 1:
supported_extensions.add("OpenGL11");
}
if ( 1 < majorVersion || 4 <= minorVersion )
supported_extensions.add("OpenGL14");
if ( 1 < majorVersion || 3 <= minorVersion )
supported_extensions.add("OpenGL13");
if ( 1 < majorVersion || 2 <= minorVersion )
supported_extensions.add("OpenGL12");
if ( 1 < majorVersion || 1 <= minorVersion )
supported_extensions.add("OpenGL11");
if ( majorVersion < 3 ) {
// Parse EXTENSIONS string
final String extensions_string = GL11.glGetString(GL11.GL_EXTENSIONS);
if ( extensions_string == null )
throw new IllegalStateException("glGetString(GL_EXTENSIONS) returned null - is there a context current?");
final StringTokenizer tokenizer = new StringTokenizer(extensions_string);
while ( tokenizer.hasMoreTokens() )
supported_extensions.add(tokenizer.nextToken());
} else {
// Use forward compatible indexed EXTENSIONS
final IntBuffer buffer = BufferUtils.createIntBuffer(16);
GL11.glGetInteger(GL30.GL_NUM_EXTENSIONS, buffer);
final int extensionCount = buffer.get(0);
for ( int i = 0; i < extensionCount; i++ )
supported_extensions.add(GL30.glGetStringi(GL11.GL_EXTENSIONS, i));
}
return supported_extensions;
}
@ -250,7 +249,7 @@ public final class GLContext {
*/
static void initNativeStubs(final Class extension_class, Set supported_extensions, String ext_name) {
resetNativeStubs(extension_class);
if (supported_extensions.contains(ext_name)) {
if ( supported_extensions.contains(ext_name) ) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
@ -281,32 +280,53 @@ public final class GLContext {
* @throws LWJGLException if context non-null, and the gl library can't be loaded or the basic GL11 functions can't be loaded
*/
public static synchronized void useContext(Object context) throws LWJGLException {
if (context == null) {
useContext(context, false);
}
/**
* Makes a GL context the current LWJGL context by loading GL function pointers. The context must be current before a call to
* this method! Instead it simply ensures that the current context is reflected accurately by GLContext's extension caps and
* function pointers. Use useContext(null) when no context is active. <p>If the context is the same as last time, then this is
* a no-op. <p>If the context has not been encountered before it will be fully initialized from scratch. Otherwise a cached set
* of caps and function pointers will be used. <p>The reference to the context is held in a weak reference; therefore if no
* strong reference exists to the GL context it will automatically be forgotten by the VM at an indeterminate point in the
* future, freeing up a little RAM.
* <p>If forwardCombatible is true, function pointers of deprecated GL11-GL21 functionality will not be loaded. Calling a deprecated
* function using the specified context will result in an <code>IllegalStateException</code>.
*
* @param context The context object, which uniquely identifies a GL context. If context is null, the native stubs are
* unloaded.
* @param forwardCombatible If the context is a forward combatible context (does not expose deprecated functionality, see XGL_ARB_create_context)
*
* @throws LWJGLException if context non-null, and the gl library can't be loaded or the basic GL11 functions can't be loaded
*/
public static synchronized void useContext(Object context, boolean forwardCombatible) throws LWJGLException {
if ( context == null ) {
ContextCapabilities.unloadAllStubs();
setCapabilities(null);
if (did_auto_load)
if ( did_auto_load )
unloadOpenGLLibrary();
return;
}
if (gl_ref_count == 0) {
if ( gl_ref_count == 0 ) {
loadOpenGLLibrary();
did_auto_load = true;
}
try {
ContextCapabilities capabilities = (ContextCapabilities)capability_cache.get(context);
if (capabilities == null) {
if ( capabilities == null ) {
/*
* The capabilities object registers itself as current. This behaviour is caused
* by a chicken-and-egg situation where the constructor needs to call GL functions
* as part of its capability discovery, but GL functions cannot be called before
* a capabilities object has been set.
*/
new ContextCapabilities();
new ContextCapabilities(forwardCombatible);
capability_cache.put(context, getCapabilities());
} else
setCapabilities(capabilities);
} catch (LWJGLException e) {
if (did_auto_load)
if ( did_auto_load )
unloadOpenGLLibrary();
throw e;
}
@ -314,7 +334,7 @@ public final class GLContext {
/** If the OpenGL reference count is 0, the library is loaded. The reference count is then incremented. */
public static synchronized void loadOpenGLLibrary() throws LWJGLException {
if (gl_ref_count == 0)
if ( gl_ref_count == 0 )
nLoadOpenGLLibrary();
gl_ref_count++;
}
@ -328,7 +348,7 @@ public final class GLContext {
* Unload the native OpenGL library unless we're on linux, since
* some drivers (NVIDIA proprietary) crash on exit when unloading the library.
*/
if (gl_ref_count == 0 && LWJGLUtil.getPlatform() != LWJGLUtil.PLATFORM_LINUX)
if ( gl_ref_count == 0 && LWJGLUtil.getPlatform() != LWJGLUtil.PLATFORM_LINUX )
nUnloadOpenGLLibrary();
}
@ -338,6 +358,7 @@ public final class GLContext {
static native void resetNativeStubs(Class clazz);
private final static class CapabilitiesCacheEntry {
Thread owner;
ContextCapabilities capabilities;
}