diff options
Diffstat (limited to 'src/net/java/games/gluegen/opengl/GLEmitter.java')
-rw-r--r-- | src/net/java/games/gluegen/opengl/GLEmitter.java | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/src/net/java/games/gluegen/opengl/GLEmitter.java b/src/net/java/games/gluegen/opengl/GLEmitter.java new file mode 100644 index 000000000..27cc07e2c --- /dev/null +++ b/src/net/java/games/gluegen/opengl/GLEmitter.java @@ -0,0 +1,330 @@ +/* + * 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.gluegen.opengl; + +import java.io.*; +import java.text.MessageFormat; +import java.util.*; +import net.java.games.gluegen.*; +import net.java.games.gluegen.cgram.types.*; + +/** + * A subclass of JavaEmitter that modifies the normal emission of C and Java + * code in order to allow a high-performance, cross-platform binding of Java + * to OpenGL. + */ +public class GLEmitter extends JavaEmitter +{ + public static final String PROCADDRESS_VAR_PREFIX = "_addressof_"; + protected static final String WRAP_PREFIX = "dispatch_"; + private TypeDictionary typedefDictionary; + private PrintWriter tableWriter; + private String tableClassName = "ProcAddressTable"; + private int numProcAddressEntries; + + public void beginFunctions(TypeDictionary typedefDictionary, + TypeDictionary structDictionary, + Map canonMap) throws Exception + { + this.typedefDictionary = typedefDictionary; + + if (getConfig().emitImpl()) { + cWriter().println("#include <assert.h> /* this include emitted by GLEmitter.java */"); + cWriter().println(); + } + + if (((GLConfiguration)getConfig()).emitProcAddressTable()) + { + beginGLProcAddressTable(); + } + super.beginFunctions(typedefDictionary, structDictionary, canonMap); + } + + public void endFunctions() throws Exception + { + if (((GLConfiguration)getConfig()).emitProcAddressTable()) + { + endGLProcAddressTable(); + } + super.endFunctions(); + } + + public void beginStructs(TypeDictionary typedefDictionary, + TypeDictionary structDictionary, + Map canonMap) throws Exception { + super.beginStructs(typedefDictionary, structDictionary, canonMap); + } + + protected JavaConfiguration createConfig() { + return new GLConfiguration(); + } + + protected Iterator generateMethodBindingEmitters(FunctionSymbol sym) throws Exception + { + Iterator defaultEmitters = super.generateMethodBindingEmitters(sym); + + // if the superclass didn't generate any bindings for the symbol, let's + // honor that (for example, the superclass might have caught an Ignore + // direction that matched the symbol's name). + if (!defaultEmitters.hasNext()) + { + return defaultEmitters; + } + + // Don't do anything special if this symbol doesn't require passing of + // Opengl procedure addresses in order to function correctly. + if (!needsProcAddressWrapper(sym) || getConfig().isUnimplemented(sym.getName())) + { + return defaultEmitters; + } + + // 9 is default # expanded bindings for void* + ArrayList modifiedEmitters = new ArrayList(9); + + if (((GLConfiguration)getConfig()).emitProcAddressTable()) + { + // emit an entry in the GL proc address table for this method. + emitGLProcAddressTableEntryForSymbol(sym); + } + + while (defaultEmitters.hasNext()) + { + FunctionEmitter emitter = (FunctionEmitter)defaultEmitters.next(); + if (emitter instanceof JavaMethodBindingEmitter) + { + JavaMethodBindingEmitter newEmitter = + generateModifiedEmitter((JavaMethodBindingEmitter)emitter); + if (newEmitter != null) { + modifiedEmitters.add(newEmitter); + } + } + else if (emitter instanceof CMethodBindingEmitter) + { + modifiedEmitters.add( + generateModifiedEmitter((CMethodBindingEmitter)emitter)); + } + else + { + throw new RuntimeException("Unexpected emitter type: " + + emitter.getClass().getName()); + } + } + + return modifiedEmitters.iterator(); + } + + /** + * Returns the name of the typedef for a pointer to the GL function + * represented by the argument. For example, if the argument is the function + * "glFuncName", the value returned will be "PFNGLFUNCNAMEPROC". This + * returns a valid string regardless of whether or not the typedef is + * actually defined. + */ + static String getGLFunctionPointerTypedefName(FunctionSymbol sym) + { + String symName = sym.getName(); + StringBuffer buf = new StringBuffer(symName.length() + 8); + buf.append("PFN"); + buf.append(symName.toUpperCase()); + buf.append("PROC"); + return buf.toString(); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private JavaMethodBindingEmitter generateModifiedEmitter(JavaMethodBindingEmitter baseJavaEmitter) + { + if (!(baseJavaEmitter instanceof JavaMethodBindingImplEmitter)) { + // We only want to wrap the native entry point in the implementation + // class, not the public interface in the interface class. + // + // If the superclass has generated a "0" emitter for this routine because + // it needs argument conversion or similar, filter that out since we will + // be providing such an emitter ourselves. Otherwise return the emitter + // unmodified. + if (baseJavaEmitter.isForNIOBufferBaseRoutine()) + return null; + return baseJavaEmitter; + } + return new JavaGLPAWrapperEmitter(baseJavaEmitter); + } + + private CMethodBindingEmitter generateModifiedEmitter(CMethodBindingEmitter baseCEmitter) + { + // The C-side JNI binding for this particular function will have an + // extra final argument, which is the address (the OpenGL procedure + // address) of the function it needs to call + CGLPAWrapperEmitter res = new CGLPAWrapperEmitter(baseCEmitter); + MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression(); + if (exp != null) { + res.setReturnValueCapacityExpression(exp); + } + return res; + } + + private boolean needsProcAddressWrapper(FunctionSymbol sym) + { + String symName = sym.getName(); + + // We should only wrap the GL symbol if its function pointer typedef has + // been defined (most likely in glext.h). + String funcPointerTypedefName = getGLFunctionPointerTypedefName(sym); + boolean shouldWrap = typedefDictionary.containsKey(funcPointerTypedefName); + //System.err.println(funcPointerTypedefName + " defined: " + shouldWrap); + + if (!shouldWrap) + { + //System.err.println("WARNING (GL): *not* run-time linking: " + sym + + // "(" + funcPointerTypedefName + " undefined)"); + } + return shouldWrap; + } + + private void beginGLProcAddressTable() throws Exception + { + String implPackageName = getImplPackageName(); + String jImplRoot = + getJavaOutputDir() + File.separator + + CodeGenUtils.packageAsPath(implPackageName); + + // HACK: until we have a way to make the impl dir different from the + // WindowsGLImpl dir and the interface dir + //tableWriter = openFile(jImplRoot + File.separator + tableClassName + ".java"); + File tmpFile = new File(jImplRoot); + tmpFile = tmpFile.getParentFile(); + tmpFile = new File(tmpFile, tableClassName + ".java"); + tableWriter = openFile(tmpFile.getPath()); + // tableWriter = openFile(jImplRoot + File.separator + ".." + File.separator + tableClassName + ".java"); + + CodeGenUtils.emitAutogeneratedWarning(tableWriter, this); + + // HACK: until we have a way to make the impl dir different from the + // WindowsGLImpl dir and the interface dir + //tableWriter.println("package " + implPackageName + ";"); + tableWriter.println("package " + getJavaPackageName() + ".impl;"); + tableWriter.println(); + tableWriter.println("/**"); + tableWriter.println(" * This table is a cache of the native pointers to OpenGL extension"); + tableWriter.println(" * functions, to be used for run-time linking of these extensions. "); + tableWriter.println(" * These pointers are obtained by the OpenGL context via a "); + tableWriter.println(" * platform-specific function (e.g., wglGetProcAddress() on Win32,"); + tableWriter.println(" * glXGetProcAddress() on X11, etc). If the member variable "); + tableWriter.println(" * " + PROCADDRESS_VAR_PREFIX + "glFuncName is non-zero then function"); + tableWriter.println(" * \"glFuncName\" can be called through the associated GLContext; "); + tableWriter.println(" * if it is 0, then the extension is not available and cannot be called."); + tableWriter.println(" */"); + tableWriter.println("public class " + tableClassName); + tableWriter.println("{"); + numProcAddressEntries = 0; + } + + private void endGLProcAddressTable() throws Exception + { + PrintWriter w = tableWriter; + w.print(" protected static long __PROCADDRESSINDEX__LASTINDEX = "); + w.print(numProcAddressEntries-1); + w.println(';'); + + w.println(); + w.println(" /**"); + w.println(" * This is a convenience method to get (by name) the native function "); + w.println(" * pointer for a given extension function. It lets you avoid "); + w.println(" * having to manually compute the " + PROCADDRESS_VAR_PREFIX + "<glFunctionName>"); + w.println(" * member variable name and look it up via reflection; it also"); + w.println(" * will throw an exception if you try to get the address of an"); + w.println(" * unknown GL extension, or one that is statically linked "); + w.println(" * and therefore does not have a valid GL procedure address. "); + w.println(" */"); + w.println(" public long getAddressFor(String glFunctionName) {"); + w.println(" String addressFieldName = net.java.games.gluegen.opengl.GLEmitter.PROCADDRESS_VAR_PREFIX + glFunctionName;"); + w.println(" try { "); + w.println(" java.lang.reflect.Field addressField = this.getClass().getField(addressFieldName);"); + w.println(" return addressField.getLong(this);"); + w.println(" } catch (Exception e) {"); + w.println(" // The user is calling a bogus function or one which is not runtime"); + w.println(" // linked (extensions and core post-OpenGL 1.1 functions are runtime linked)"); + w.println(" if (!FunctionAvailabilityCache.isPartOfGLCore(\"1.1\", glFunctionName)) "); + w.println(" {"); + w.println(" throw new RuntimeException(" ); + w.println(" \"WARNING: Address query failed for \\\"\" + glFunctionName +"); + w.println(" \"\\\"; either it's not runtime linked or it is not a known \" +"); + w.println(" \"OpenGL function\", e);"); + w.println(" }"); + w.println(" } "); + w.println(" assert(false); // should never get this far"); + w.println(" return 0;"); + w.println(" }"); + + w.println("} // end of class " + tableClassName); + w.flush(); + w.close(); + } + + private void emitGLProcAddressTableEntryForSymbol(FunctionSymbol cFunc) + { + tableWriter.print(" public static long "); + tableWriter.print(PROCADDRESS_VAR_PREFIX); + tableWriter.print(cFunc.getName()); + tableWriter.println(";"); + ++numProcAddressEntries; + } + + protected static class GLConfiguration extends JavaConfiguration + { + private boolean emitProcAddressTable = false; + + protected void dispatch(String cmd, StringTokenizer tok, File file, String filename, int lineNo) throws IOException { + if (cmd.equalsIgnoreCase("EmitProcAddressTable")) + { + emitProcAddressTable = + readBoolean("EmitProcAddressTable", tok, filename, lineNo).booleanValue(); + } + else + { + super.dispatch(cmd,tok,file,filename,lineNo); + } + } + + public boolean emitProcAddressTable() { return emitProcAddressTable; } + } // end class GLConfiguration +} + |