diff options
Diffstat (limited to 'opengl/tools/glgen/src')
-rw-r--r-- | opengl/tools/glgen/src/CFunc.java | 155 | ||||
-rw-r--r-- | opengl/tools/glgen/src/CType.java | 85 | ||||
-rw-r--r-- | opengl/tools/glgen/src/CodeEmitter.java | 8 | ||||
-rw-r--r-- | opengl/tools/glgen/src/GenerateGL.java | 164 | ||||
-rw-r--r-- | opengl/tools/glgen/src/JFunc.java | 148 | ||||
-rw-r--r-- | opengl/tools/glgen/src/JType.java | 139 | ||||
-rw-r--r-- | opengl/tools/glgen/src/JniCodeEmitter.java | 1086 | ||||
-rw-r--r-- | opengl/tools/glgen/src/ParameterChecker.java | 28 |
8 files changed, 1813 insertions, 0 deletions
diff --git a/opengl/tools/glgen/src/CFunc.java b/opengl/tools/glgen/src/CFunc.java new file mode 100644 index 0000000..0794f41 --- /dev/null +++ b/opengl/tools/glgen/src/CFunc.java @@ -0,0 +1,155 @@ +
+import java.util.*;
+
+public class CFunc {
+
+ String original;
+
+ CType ftype;
+ String fname;
+
+ List<String> argNames = new ArrayList<String>();
+ List<CType> argTypes = new ArrayList<CType>();
+
+ boolean hasPointerArg = false;
+ boolean hasTypedPointerArg = false;
+
+ public CFunc(String original) {
+ this.original = original;
+ }
+
+ public String getOriginal() {
+ return original;
+ }
+
+ public void setName(String fname) {
+ this.fname = fname;
+ }
+
+ public String getName() {
+ return fname;
+ }
+
+ public void setType(CType ftype) {
+ this.ftype = ftype;
+ }
+
+ public CType getType() {
+ return ftype;
+ }
+
+ public void addArgument(String argName, CType argType) {
+ argNames.add(argName);
+ argTypes.add(argType);
+
+ if (argType.isPointer()) {
+ hasPointerArg = true;
+ }
+ if (argType.isTypedPointer()) {
+ hasTypedPointerArg = true;
+ }
+ }
+
+ public int getNumArgs() {
+ return argNames.size();
+ }
+
+ public int getArgIndex(String name) {
+ int len = argNames.size();
+ for (int i = 0; i < len; i++) {
+ if (name.equals(argNames.get(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public String getArgName(int index) {
+ return argNames.get(index);
+ }
+
+ public CType getArgType(int index) {
+ return argTypes.get(index);
+ }
+
+ public boolean hasPointerArg() {
+ return hasPointerArg;
+ }
+
+ public boolean hasTypedPointerArg() {
+ return hasTypedPointerArg;
+ }
+
+ public String toString() {
+ String s = "Function " + fname + " returns " + ftype + ": ";
+ for (int i = 0; i < argNames.size(); i++) {
+ if (i > 0) {
+ s += ", ";
+ }
+ s += argTypes.get(i) + " " + argNames.get(i);
+ }
+ return s;
+ }
+
+ public static CFunc parseCFunc(String s) {
+ CFunc cfunc = new CFunc(s);
+ String[] tokens = s.split("\\s");
+
+ int i = 0;
+ CType ftype = new CType();
+ String ftypeName = tokens[i++];
+ if (ftypeName.equals("const")) {
+ ftype.setIsConst(true);
+ ftypeName = tokens[i++];
+ }
+ ftype.setBaseType(ftypeName);
+
+ String fname = tokens[i++];
+ if (fname.equals("*")) {
+ ftype.setIsPointer(true);
+ fname = tokens[i++];
+ }
+
+ cfunc.setName(fname);
+ cfunc.setType(ftype);
+
+ while (i < tokens.length) {
+ String tok = tokens[i++];
+
+ if (tok.equals("(")) {
+ continue;
+ }
+ if (tok.equals(")")) {
+ break;
+ }
+
+ CType argType = new CType();
+
+ String argTypeName = tok;
+ String argName = "";
+
+ if (argTypeName.equals("const")) {
+ argType.setIsConst(true);
+ argTypeName = tokens[i++];
+ }
+ argType.setBaseType(argTypeName);
+
+ if (argTypeName.equals("void")) {
+ break;
+ }
+
+ argName = tokens[i++];
+ if (argName.startsWith("*")) {
+ argType.setIsPointer(true);
+ argName = argName.substring(1, argName.length());
+ }
+ if (argName.endsWith(",")) {
+ argName = argName.substring(0, argName.length() - 1);
+ }
+
+ cfunc.addArgument(argName, argType);
+ }
+
+ return cfunc;
+ }
+}
diff --git a/opengl/tools/glgen/src/CType.java b/opengl/tools/glgen/src/CType.java new file mode 100644 index 0000000..331ec62 --- /dev/null +++ b/opengl/tools/glgen/src/CType.java @@ -0,0 +1,85 @@ +
+public class CType {
+
+ String baseType;
+ boolean isConst;
+ boolean isPointer;
+
+ public CType() {
+ }
+
+ public CType(String baseType) {
+ setBaseType(baseType);
+ }
+
+ public CType(String baseType, boolean isConst, boolean isPointer) {
+ setBaseType(baseType);
+ setIsConst(isConst);
+ setIsPointer(isPointer);
+ }
+
+ public String getDeclaration() {
+ return baseType + (isPointer ? " *" : "");
+ }
+
+ public void setIsConst(boolean isConst) {
+ this.isConst = isConst;
+ }
+
+ public boolean isConst() {
+ return isConst;
+ }
+
+ public void setIsPointer(boolean isPointer) {
+ this.isPointer = isPointer;
+ }
+
+ public boolean isPointer() {
+ return isPointer;
+ }
+
+ boolean isVoid() {
+ String baseType = getBaseType();
+ return baseType.equals("GLvoid") ||
+ baseType.equals("void");
+ }
+
+ public boolean isTypedPointer() {
+ return isPointer() && !isVoid();
+ }
+
+ public void setBaseType(String baseType) {
+ this.baseType = baseType;
+ }
+
+ public String getBaseType() {
+ return baseType;
+ }
+
+ public String toString() {
+ String s = "";
+ if (isConst()) {
+ s += "const ";
+ }
+ s += baseType;
+ if (isPointer()) {
+ s += "*";
+ }
+
+ return s;
+ }
+
+ public int hashCode() {
+ return baseType.hashCode() ^ (isPointer ? 2 : 0) ^ (isConst ? 1 : 0);
+ }
+
+ public boolean equals(Object o) {
+ if (o != null && o instanceof CType) {
+ CType c = (CType)o;
+ return baseType.equals(c.baseType) &&
+ isPointer() == c.isPointer() &&
+ isConst() == c.isConst();
+ }
+ return false;
+ }
+}
diff --git a/opengl/tools/glgen/src/CodeEmitter.java b/opengl/tools/glgen/src/CodeEmitter.java new file mode 100644 index 0000000..3e9b90a --- /dev/null +++ b/opengl/tools/glgen/src/CodeEmitter.java @@ -0,0 +1,8 @@ +
+public interface CodeEmitter {
+
+ void setVersion(int version, boolean ext, boolean pack);
+ void emitCode(CFunc cfunc, String original);
+ void addNativeRegistration(String fname);
+ void emitNativeRegistration();
+}
diff --git a/opengl/tools/glgen/src/GenerateGL.java b/opengl/tools/glgen/src/GenerateGL.java new file mode 100644 index 0000000..657ee6e --- /dev/null +++ b/opengl/tools/glgen/src/GenerateGL.java @@ -0,0 +1,164 @@ +
+import java.io.*;
+import java.util.*;
+
+public class GenerateGL {
+
+ static void copy(String filename, PrintStream out) throws IOException {
+ BufferedReader br = new BufferedReader(new FileReader(filename));
+ String s;
+ while ((s = br.readLine()) != null) {
+ out.println(s);
+ }
+ }
+
+ private static void emit(int version, boolean ext, boolean pack,
+ CodeEmitter emitter,
+ BufferedReader specReader,
+ PrintStream glStream,
+ PrintStream glImplStream,
+ PrintStream cStream) throws Exception {
+ String s = null;
+ int counter = 0;
+ while ((s = specReader.readLine()) != null) {
+ if (s.trim().startsWith("//")) {
+ continue;
+ }
+
+ CFunc cfunc = CFunc.parseCFunc(s);
+
+ String fname = cfunc.getName();
+ File f = new File("stubs/" + fname +
+ ".java-1" + version + "-if");
+ if (f.exists()) {
+ System.out.println("Special-casing function " + fname);
+ copy("stubs/" + fname +
+ ".java-1" + version + "-if", glStream);
+ copy("stubs/" + fname + ".java-impl", glImplStream);
+ copy("stubs/" + fname + ".cpp", cStream);
+
+ // Register native function names
+ // This should be improved to require fewer discrete files
+ String filename = "stubs/" + fname + ".nativeReg";
+ BufferedReader br =
+ new BufferedReader(new FileReader(filename));
+ String nfunc;
+ while ((nfunc = br.readLine()) != null) {
+ emitter.addNativeRegistration(nfunc);
+ }
+ } else {
+ emitter.setVersion(version, ext, pack);
+ emitter.emitCode(cfunc, s);
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ String classPathName = "com/google/android/gles_jni/GLImpl";
+ boolean useContextPointer = true;
+
+ int aidx = 0;
+ while (args[aidx].charAt(0) == '-') {
+ switch (args[aidx].charAt(1)) {
+ case 'c':
+ useContextPointer = false;
+ break;
+
+ default:
+ System.err.println("Unknown flag: " + args[aidx]);
+ System.exit(1);
+ }
+
+ aidx++;
+ }
+
+ System.out.println("useContextPointer = " + useContextPointer);
+
+ BufferedReader spec10Reader =
+ new BufferedReader(new FileReader(args[aidx++]));
+ BufferedReader spec10ExtReader =
+ new BufferedReader(new FileReader(args[aidx++]));
+ BufferedReader spec11Reader =
+ new BufferedReader(new FileReader(args[aidx++]));
+ BufferedReader spec11ExtReader =
+ new BufferedReader(new FileReader(args[aidx++]));
+ BufferedReader spec11ExtPackReader =
+ new BufferedReader(new FileReader(args[aidx++]));
+ BufferedReader checksReader =
+ new BufferedReader(new FileReader(args[aidx++]));
+
+ String gl10Filename = "javax/microedition/khronos/opengles/GL10.java";
+ String gl10ExtFilename =
+ "javax/microedition/khronos/opengles/GL10Ext.java";
+ String gl11Filename = "javax/microedition/khronos/opengles/GL11.java";
+ String gl11ExtFilename =
+ "javax/microedition/khronos/opengles/GL11Ext.java";
+ String gl11ExtPackFilename =
+ "javax/microedition/khronos/opengles/GL11ExtensionPack.java";
+ String glImplFilename = "com/google/android/gles_jni/GLImpl.java";
+ String cFilename = "com_google_android_gles_jni_GLImpl.cpp";
+
+ PrintStream gl10Stream =
+ new PrintStream(new FileOutputStream("out/" + gl10Filename));
+ PrintStream gl10ExtStream =
+ new PrintStream(new FileOutputStream("out/" + gl10ExtFilename));
+ PrintStream gl11Stream =
+ new PrintStream(new FileOutputStream("out/" + gl11Filename));
+ PrintStream gl11ExtStream =
+ new PrintStream(new FileOutputStream("out/" + gl11ExtFilename));
+ PrintStream gl11ExtPackStream =
+ new PrintStream(new FileOutputStream("out/" + gl11ExtPackFilename));
+ PrintStream glImplStream =
+ new PrintStream(new FileOutputStream("out/" + glImplFilename));
+ PrintStream cStream =
+ new PrintStream(new FileOutputStream("out/" + cFilename));
+
+ ParameterChecker checker = new ParameterChecker(checksReader);
+
+ CodeEmitter emitter =
+ new JniCodeEmitter(classPathName,
+ checker,
+ gl10Stream, gl10ExtStream,
+ gl11Stream, gl11ExtStream, gl11ExtPackStream,
+ glImplStream, cStream,
+ useContextPointer);
+
+ gl10Stream.println("/* //device/java/android/" + gl10Filename);
+ gl10ExtStream.println("/* //device/java/android/" + gl10ExtFilename);
+ gl11Stream.println("/* //device/java/android/" + gl11Filename);
+ gl11ExtStream.println("/* //device/java/android/" + gl11ExtFilename);
+ gl11ExtPackStream.println("/* //device/java/android/" +
+ gl11ExtPackFilename);
+ glImplStream.println("/* //device/java/android/" + glImplFilename);
+ cStream.println("/* //device/libs/android_runtime/" + cFilename);
+
+ copy("stubs/GL10Header.java-if", gl10Stream);
+ copy("stubs/GL10ExtHeader.java-if", gl10ExtStream);
+ copy("stubs/GL11Header.java-if", gl11Stream);
+ copy("stubs/GL11ExtHeader.java-if", gl11ExtStream);
+ copy("stubs/GL11ExtensionPackHeader.java-if", gl11ExtPackStream);
+ copy("stubs/GLImplHeader.java-impl", glImplStream);
+ copy("stubs/GLCHeader.cpp", cStream);
+
+ emit(0, false, false,
+ emitter, spec10Reader, gl10Stream, glImplStream, cStream);
+ emit(0, true, false,
+ emitter, spec10ExtReader, gl10ExtStream, glImplStream, cStream);
+ emit(1, false, false,
+ emitter, spec11Reader, gl11Stream, glImplStream, cStream);
+ emit(1, true, false,
+ emitter, spec11ExtReader, gl11ExtStream, glImplStream, cStream);
+ emit(1, true, true,
+ emitter, spec11ExtPackReader, gl11ExtPackStream, glImplStream,
+ cStream);
+
+ emitter.emitNativeRegistration();
+
+ gl10Stream.println("}");
+ gl10ExtStream.println("}");
+ gl11Stream.println("}");
+ gl11ExtStream.println("}");
+ gl11ExtPackStream.println("}");
+ glImplStream.println("}");
+ }
+}
diff --git a/opengl/tools/glgen/src/JFunc.java b/opengl/tools/glgen/src/JFunc.java new file mode 100644 index 0000000..42d466c --- /dev/null +++ b/opengl/tools/glgen/src/JFunc.java @@ -0,0 +1,148 @@ +
+import java.util.ArrayList;
+import java.util.List;
+
+public class JFunc {
+
+ String className = "com.google.android.gles_jni.GL11Impl";
+
+ CFunc cfunc;
+ JType ftype;
+ String fname;
+
+ List<String> argNames = new ArrayList<String>();
+ List<JType> argTypes = new ArrayList<JType>();
+ List<Integer> argCIndices = new ArrayList<Integer>();
+
+ boolean hasBufferArg = false;
+ boolean hasTypedBufferArg = false;
+ ArrayList<String> bufferArgNames = new ArrayList<String>();
+
+ public JFunc(CFunc cfunc) {
+ this.cfunc = cfunc;
+ }
+
+ public CFunc getCFunc() {
+ return cfunc;
+ }
+
+ public void setName(String fname) {
+ this.fname = fname;
+ }
+
+ public String getName() {
+ return fname;
+ }
+
+ public void setType(JType ftype) {
+ this.ftype = ftype;
+ }
+
+ public JType getType() {
+ return ftype;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public boolean hasBufferArg() {
+ return hasBufferArg;
+ }
+
+ public boolean hasTypedBufferArg() {
+ return hasTypedBufferArg;
+ }
+
+ public String getBufferArgName(int index) {
+ return bufferArgNames.get(index);
+ }
+
+ public void addArgument(String argName, JType argType, int cindex) {
+ argNames.add(argName);
+ argTypes.add(argType);
+ argCIndices.add(new Integer(cindex));
+
+ if (argType.isBuffer()) {
+ hasBufferArg = true;
+ bufferArgNames.add(argName);
+ }
+ if (argType.isTypedBuffer()) {
+ hasTypedBufferArg = true;
+ bufferArgNames.add(argName);
+ }
+ }
+
+ public int getNumArgs() {
+ return argNames.size();
+ }
+
+ public int getArgIndex(String name) {
+ int len = argNames.size();
+ for (int i = 0; i < len; i++) {
+ if (name.equals(argNames.get(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public String getArgName(int index) {
+ return argNames.get(index);
+ }
+
+ public JType getArgType(int index) {
+ return argTypes.get(index);
+ }
+
+ public int getArgCIndex(int index) {
+ return argCIndices.get(index).intValue();
+ }
+
+ public static JFunc convert(CFunc cfunc, boolean useArray) {
+ JFunc jfunc = new JFunc(cfunc);
+ jfunc.setName(cfunc.getName());
+ jfunc.setType(JType.convert(cfunc.getType(), false));
+
+ int numArgs = cfunc.getNumArgs();
+ int numOffsets = 0;
+ for (int i = 0; i < numArgs; i++) {
+ CType cArgType = cfunc.getArgType(i);
+ if (cArgType.isTypedPointer() && useArray) {
+ ++numOffsets;
+ }
+ }
+
+ for (int i = 0; i < numArgs; i++) {
+ String cArgName = cfunc.getArgName(i);
+ CType cArgType = cfunc.getArgType(i);
+
+ jfunc.addArgument(cArgName, JType.convert(cArgType, useArray), i);
+ if (cArgType.isTypedPointer() && useArray) {
+ if (numOffsets > 1) {
+ jfunc.addArgument(cArgName + "Offset", new JType("int"), i);
+ } else {
+ jfunc.addArgument("offset", new JType("int"), i);
+ }
+ }
+ }
+
+ return jfunc;
+ }
+
+ public String toString() {
+ String s = "Function " + fname + " returns " + ftype + ": ";
+ for (int i = 0; i < argNames.size(); i++) {
+ if (i > 0) {
+ s += ", ";
+ }
+ s += argTypes.get(i) + " " + argNames.get(i);
+ }
+ return s;
+ }
+
+}
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java new file mode 100644 index 0000000..a16d440 --- /dev/null +++ b/opengl/tools/glgen/src/JType.java @@ -0,0 +1,139 @@ +
+import java.util.HashMap;
+
+public class JType {
+
+ String baseType;
+ boolean isArray;
+ boolean isClass;
+
+ static HashMap<CType,JType> typeMapping = new HashMap<CType,JType>();
+ static HashMap<CType,JType> arrayTypeMapping = new HashMap<CType,JType>();
+
+ static {
+ // Primitive types
+ typeMapping.put(new CType("GLbitfield"), new JType("int"));
+ typeMapping.put(new CType("GLboolean"), new JType("boolean"));
+ typeMapping.put(new CType("GLclampf"), new JType("float"));
+ typeMapping.put(new CType("GLclampx"), new JType("int"));
+ typeMapping.put(new CType("GLenum"), new JType("int"));
+ typeMapping.put(new CType("GLfloat"), new JType("float"));
+ typeMapping.put(new CType("GLfixed"), new JType("int"));
+ typeMapping.put(new CType("GLint"), new JType("int"));
+ typeMapping.put(new CType("GLintptr"), new JType("int"));
+ typeMapping.put(new CType("GLshort"), new JType("short"));
+ typeMapping.put(new CType("GLsizei"), new JType("int"));
+ typeMapping.put(new CType("GLsizeiptr"), new JType("int"));
+ typeMapping.put(new CType("GLubyte"), new JType("byte"));
+ typeMapping.put(new CType("GLuint"), new JType("int"));
+ typeMapping.put(new CType("void"), new JType("void"));
+ typeMapping.put(new CType("GLubyte", true, true), new JType("String"));
+
+ // Untyped pointers map to untyped Buffers
+ typeMapping.put(new CType("GLvoid", true, true),
+ new JType("java.nio.Buffer", true, false));
+ typeMapping.put(new CType("GLvoid", false, true),
+ new JType("java.nio.Buffer", true, false));
+ typeMapping.put(new CType("void", false, true),
+ new JType("java.nio.Buffer", true, false));
+
+ // Typed pointers map to typed Buffers
+ typeMapping.put(new CType("GLboolean", false, true),
+ new JType("java.nio.IntBuffer", true, false));
+ typeMapping.put(new CType("GLfixed", false, true),
+ new JType("java.nio.IntBuffer", true, false));
+ typeMapping.put(new CType("GLfixed", true, true),
+ new JType("java.nio.IntBuffer", true, false));
+ typeMapping.put(new CType("GLfloat", false, true),
+ new JType("java.nio.FloatBuffer", true, false));
+ typeMapping.put(new CType("GLfloat", true, true),
+ new JType("java.nio.FloatBuffer", true, false));
+ typeMapping.put(new CType("GLint", false, true),
+ new JType("java.nio.IntBuffer", true, false));
+ typeMapping.put(new CType("GLint", true, true),
+ new JType("java.nio.IntBuffer", true, false));
+ typeMapping.put(new CType("GLuint", false, true),
+ new JType("java.nio.IntBuffer", true, false));
+ typeMapping.put(new CType("GLuint", true, true),
+ new JType("java.nio.IntBuffer", true, false));
+ typeMapping.put(new CType("GLshort", true, true),
+ new JType("java.nio.ShortBuffer", true, false));
+
+ // Typed pointers map to arrays + offsets
+ arrayTypeMapping.put(new CType("GLboolean", false, true),
+ new JType("boolean", false, true));
+ arrayTypeMapping.put(new CType("GLfixed", true, true), new JType("int", false, true));
+ arrayTypeMapping.put(new CType("GLfixed", false, true), new JType("int", false, true));
+ arrayTypeMapping.put(new CType("GLfloat", false, true), new JType("float", false, true));
+ arrayTypeMapping.put(new CType("GLfloat", true, true), new JType("float", false, true));
+ arrayTypeMapping.put(new CType("GLint", false, true), new JType("int", false, true));
+ arrayTypeMapping.put(new CType("GLint", true, true), new JType("int", false, true));
+ arrayTypeMapping.put(new CType("GLshort", true, true), new JType("short", false, true));
+ arrayTypeMapping.put(new CType("GLuint", false, true), new JType("int", false, true));
+ arrayTypeMapping.put(new CType("GLuint", true, true), new JType("int", false, true));
+ arrayTypeMapping.put(new CType("GLintptr"), new JType("int", false, true));
+ arrayTypeMapping.put(new CType("GLsizeiptr"), new JType("int", false, true));
+ }
+
+ public JType() {
+ }
+
+ public JType(String primitiveTypeName) {
+ this.baseType = primitiveTypeName;
+ this.isClass = false;
+ this.isArray = false;
+ }
+
+ public JType(String primitiveTypeName, boolean isClass, boolean isArray) {
+ this.baseType = primitiveTypeName;
+ this.isClass = isClass;
+ this.isArray = isArray;
+ }
+
+ public String getBaseType() {
+ return baseType;
+ }
+
+ public String toString() {
+ return baseType + (isArray ? "[]" : "");
+ }
+
+ public boolean isArray() {
+ return isArray;
+ }
+
+ public boolean isClass() {
+ return isClass;
+ }
+
+ public boolean isPrimitive() {
+ return !isClass() && !isArray();
+ }
+
+ public boolean isVoid() {
+ return baseType.equals("void");
+ }
+
+ public boolean isBuffer() {
+ return baseType.indexOf("Buffer") != -1;
+ }
+
+ public boolean isTypedBuffer() {
+ return !baseType.equals("java.nio.Buffer") &&
+ (baseType.indexOf("Buffer") != -1);
+ }
+
+ public static JType convert(CType ctype, boolean useArray) {
+ JType javaType = null;
+ if (useArray) {
+ javaType = arrayTypeMapping.get(ctype);
+ }
+ if (javaType == null) {
+ javaType = typeMapping.get(ctype);
+ }
+ if (javaType == null) {
+ throw new RuntimeException("Unsupported C type: " + ctype);
+ }
+ return javaType;
+ }
+}
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java new file mode 100644 index 0000000..33b9a3e --- /dev/null +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -0,0 +1,1086 @@ +import java.io.PrintStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +/** + * Emits a Java interface and Java & C implementation for a C function. + * + * <p> The Java interface will have Buffer and array variants for functions that + * have a typed pointer argument. The array variant will convert a single "<type> *data" + * argument to a pair of arguments "<type>[] data, int offset". + */ +public class JniCodeEmitter implements CodeEmitter { + + // If true, use C++ style for calling through a JNIEnv *: + // env->Func(...) + // If false, use C style: + // (*env)->Func(env, ...) + static final boolean mUseCPlusPlus = true; + + boolean mUseContextPointer = true; + + String mClassPathName; + + ParameterChecker mChecker; + PrintStream mJava10InterfaceStream; + PrintStream mJava10ExtInterfaceStream; + PrintStream mJava11InterfaceStream; + PrintStream mJava11ExtInterfaceStream; + PrintStream mJava11ExtPackInterfaceStream; + PrintStream mJavaImplStream; + PrintStream mCStream; + + PrintStream mJavaInterfaceStream; + + List<String> nativeRegistrations = new ArrayList<String>(); + + boolean needsExit; + + static String indent = " "; + + HashSet<String> mFunctionsEmitted = new HashSet<String>(); + + /** + * @param java10InterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 functions + * @param java10ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 extension functions + * @param java11InterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 functions + * @param java11ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension functions + * @param java11ExtPackInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension Pack functions + * @param javaImplStream the PrintStream to which to emit the Java implementation + * @param cStream the PrintStream to which to emit the C implementation + */ + public JniCodeEmitter(String classPathName, + ParameterChecker checker, + PrintStream java10InterfaceStream, + PrintStream java10ExtInterfaceStream, + PrintStream java11InterfaceStream, + PrintStream java11ExtInterfaceStream, + PrintStream java11ExtPackInterfaceStream, + PrintStream javaImplStream, + PrintStream cStream, + boolean useContextPointer) { + mClassPathName = classPathName; + mChecker = checker; + mJava10InterfaceStream = java10InterfaceStream; + mJava10ExtInterfaceStream = java10ExtInterfaceStream; + mJava11InterfaceStream = java11InterfaceStream; + mJava11ExtInterfaceStream = java11ExtInterfaceStream; + mJava11ExtPackInterfaceStream = java11ExtPackInterfaceStream; + mJavaImplStream = javaImplStream; + mCStream = cStream; + mUseContextPointer = useContextPointer; + } + + public void setVersion(int version, boolean ext, boolean pack) { + if (version == 0) { + mJavaInterfaceStream = ext ? mJava10ExtInterfaceStream : + mJava10InterfaceStream; + } else if (version == 1) { + mJavaInterfaceStream = ext ? + (pack ? mJava11ExtPackInterfaceStream : + mJava11ExtInterfaceStream) : + mJava11InterfaceStream; + } else { + throw new RuntimeException("Bad version: " + version); + } + } + + public void emitCode(CFunc cfunc, String original) { + JFunc jfunc; + String signature; + boolean duplicate; + + if (cfunc.hasTypedPointerArg()) { + jfunc = JFunc.convert(cfunc, true); + + // Don't emit duplicate functions + // These may appear because they are defined in multiple + // Java interfaces (e.g., GL11/GL11ExtensionPack) + signature = jfunc.toString(); + duplicate = false; + if (mFunctionsEmitted.contains(signature)) { + duplicate = true; + } else { + mFunctionsEmitted.add(signature); + } + + if (!duplicate) { + emitNativeDeclaration(jfunc, mJavaImplStream); + emitJavaCode(jfunc, mJavaImplStream); + } + emitJavaInterfaceCode(jfunc, mJavaInterfaceStream); + if (!duplicate) { + emitJniCode(jfunc, mCStream); + } + } + + jfunc = JFunc.convert(cfunc, false); + + signature = jfunc.toString(); + duplicate = false; + if (mFunctionsEmitted.contains(signature)) { + duplicate = true; + } else { + mFunctionsEmitted.add(signature); + } + + if (!duplicate) { + emitNativeDeclaration(jfunc, mJavaImplStream); + } + emitJavaInterfaceCode(jfunc, mJavaInterfaceStream); + if (!duplicate) { + emitJavaCode(jfunc, mJavaImplStream); + emitJniCode(jfunc, mCStream); + } + } + + public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { + out.println(" // C function " + jfunc.getCFunc().getOriginal()); + out.println(); + + emitFunction(jfunc, out, true, false); + } + + public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) { + emitFunction(jfunc, out, false, true); + } + + public void emitJavaCode(JFunc jfunc, PrintStream out) { + emitFunction(jfunc, out, false, false); + } + + void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray ) { + boolean isVoid = jfunc.getType().isVoid(); + boolean isPointerFunc = jfunc.getName().endsWith("Pointer") && + jfunc.getCFunc().hasPointerArg(); + + if (!isVoid) { + out.println(iii + + jfunc.getType() + " _returnValue;"); + } + out.println(iii + + (isVoid ? "" : "_returnValue = ") + + jfunc.getName() + + (isPointerFunc ? "Bounds" : "" ) + + "("); + + int numArgs = jfunc.getNumArgs(); + for (int i = 0; i < numArgs; i++) { + String argName = jfunc.getArgName(i); + JType argType = jfunc.getArgType(i); + + if (grabArray && argType.isTypedBuffer()) { + String typeName = argType.getBaseType(); + typeName = typeName.substring(9, typeName.length() - 6); + out.println(iii + indent + "get" + typeName + "Array(" + argName + "),"); + out.print(iii + indent + "getOffset(" + argName + ")"); + } else { + out.print(iii + indent + argName); + } + if (i == numArgs - 1) { + if (isPointerFunc) { + out.println(","); + out.println(iii + indent + argName + ".remaining()"); + } else { + out.println(); + } + } else { + out.println(","); + } + } + + out.println(iii + ");"); + } + + void printIfcheckPostamble(PrintStream out, boolean isBuffer, + boolean emitExceptionCheck, String iii) { + printIfcheckPostamble(out, isBuffer, emitExceptionCheck, + "offset", "_remaining", iii); + } + + void printIfcheckPostamble(PrintStream out, boolean isBuffer, + boolean emitExceptionCheck, + String offset, String remaining, String iii) { + out.println(iii + " default:"); + out.println(iii + " _needed = 0;"); + out.println(iii + " break;"); + out.println(iii + "}"); + + out.println(iii + "if (" + remaining + " < _needed) {"); + if (emitExceptionCheck) { + out.println(iii + indent + "_exception = 1;"); + } + out.println(iii + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + "IAEClass, " + + "\"" + + (isBuffer ? + "remaining()" : "length - " + offset) + + " < needed\");"); + out.println(iii + indent + "goto exit;"); + needsExit = true; + out.println(iii + "}"); + } + + boolean isNullAllowed(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].equals("return")) { + index += 2; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("unsupported")) { + index += 1; + } else if (checks[index].equals("nullAllowed")) { + return true; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + return false; + } + + String getErrorReturnValue(CFunc cfunc) { + CType returnType = cfunc.getType(); + boolean isVoid = returnType.isVoid(); + if (isVoid) { + return null; + } + + String[] checks = mChecker.getChecks(cfunc.getName()); + + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].equals("return")) { + return checks[index + 1]; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("unsupported")) { + index += 1; + } else if (checks[index].equals("nullAllowed")) { + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + + return null; + } + + boolean isUnsupportedFunc(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].equals("unsupported")) { + return true; + } else if (checks[index].equals("return")) { + index += 2; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("nullAllowed")) { + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + return false; + } + + void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, + boolean isBuffer, boolean emitExceptionCheck, + String offset, String remaining, String iii) { + CType returnType = cfunc.getType(); + boolean isVoid = returnType.isVoid(); + + String[] checks = mChecker.getChecks(cfunc.getName()); + String checkVar; + String retval = getErrorReturnValue(cfunc); + + boolean lastWasIfcheck = false; + + int index = 1; + if (checks != null) { + boolean remainingDeclared = false; + boolean nullCheckDeclared = false; + boolean offsetChecked = false; + while (index < checks.length) { + if (checks[index].startsWith("check")) { + if (lastWasIfcheck) { + printIfcheckPostamble(out, isBuffer, emitExceptionCheck, + offset, remaining, iii); + } + lastWasIfcheck = false; + if (cname != null && !cname.equals(checks[index + 1])) { + index += 3; + continue; + } + out.println(iii + "if (" + remaining + " < " + + checks[index + 2] + + ") {"); + if (emitExceptionCheck) { + out.println(iii + indent + "_exception = 1;"); + } + String exceptionClassName = "IAEClass"; + // If the "check" keyword was of the form + // "check_<class name>", use the class name in the + // exception to be thrown + int underscore = checks[index].indexOf('_'); + if (underscore >= 0) { + exceptionClassName = checks[index].substring(underscore + 1) + "Class"; + } + out.println(iii + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + exceptionClassName + ", " + + "\"" + + (isBuffer ? + "remaining()" : "length - " + offset) + + " < " + checks[index + 2] + + "\");"); + + out.println(iii + indent + "goto exit;"); + needsExit = true; + out.println(iii + "}"); + + index += 3; + } else if (checks[index].equals("ifcheck")) { + String[] matches = checks[index + 4].split(","); + + if (!lastWasIfcheck) { + out.println(iii + "int _needed;"); + out.println(iii + + "switch (" + + checks[index + 3] + + ") {"); + } + + for (int i = 0; i < matches.length; i++) { + out.println("#if defined(" + matches[i] + ")"); + out.println(iii + + " case " + + matches[i] + + ":"); + out.println("#endif // defined(" + matches[i] + ")"); + } + out.println(iii + + " _needed = " + + checks[index + 2] + + ";"); + out.println(iii + + " break;"); + + lastWasIfcheck = true; + index += 5; + } else if (checks[index].equals("return")) { + // ignore + index += 2; + } else if (checks[index].equals("unsupported")) { + // ignore + index += 1; + } else if (checks[index].equals("nullAllowed")) { + // ignore + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + + if (lastWasIfcheck) { + printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); + } + } + + boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, + List<Integer> nonPrimitiveArgs) { + if (nonPrimitiveArgs.size() > 0) { + for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + if (jfunc.getArgType(idx).isArray()) { + if (!cfunc.getArgType(cIndex).isConst()) { + return true; + } + } else if (jfunc.getArgType(idx).isBuffer()) { + if (!cfunc.getArgType(cIndex).isConst()) { + return true; + } + } + } + } + + return false; + } + + /** + * Emit a function in several variants: + * + * if nativeDecl: public native <returntype> func(args); + * + * if !nativeDecl: + * if interfaceDecl: public <returntype> func(args); + * if !interfaceDecl: public <returntype> func(args) { body } + */ + void emitFunction(JFunc jfunc, + PrintStream out, + boolean nativeDecl, boolean interfaceDecl) { + boolean isPointerFunc = + jfunc.getName().endsWith("Pointer") && + jfunc.getCFunc().hasPointerArg(); + + if (!nativeDecl && !interfaceDecl && !isPointerFunc) { + // If it's not a pointer function, we've already emitted it + // with nativeDecl == true + return; + } + + if (isPointerFunc) { + out.println(indent + + (nativeDecl ? "private native " : + (interfaceDecl ? "" : "public ")) + + jfunc.getType() + " " + + jfunc.getName() + + (nativeDecl ? "Bounds" : "") + + "("); + } else { + out.println(indent + + (nativeDecl ? "public native " : + (interfaceDecl ? "" : "public ")) + + jfunc.getType() + " " + + jfunc.getName() + + "("); + } + + int numArgs = jfunc.getNumArgs(); + for (int i = 0; i < numArgs; i++) { + String argName = jfunc.getArgName(i); + JType argType = jfunc.getArgType(i); + + out.print(indent + indent + argType + " " + argName); + if (i == numArgs - 1) { + if (isPointerFunc && nativeDecl) { + out.println(","); + out.println(indent + indent + "int remaining"); + } else { + out.println(); + } + } else { + out.println(","); + } + } + + if (nativeDecl || interfaceDecl) { + out.println(indent + ");"); + } else { + out.println(indent + ") {"); + + String iii = indent + indent; + + String fname = jfunc.getName(); + if (isPointerFunc) { + // TODO - deal with VBO variants + if (fname.equals("glColorPointer")) { + out.println(iii + "if ((size == 4) &&"); + out.println(iii + " ((type == GL_FLOAT) ||"); + out.println(iii + " (type == GL_UNSIGNED_BYTE) ||"); + out.println(iii + " (type == GL_FIXED)) &&"); + out.println(iii + " (stride >= 0)) {"); + out.println(iii + indent + "_colorPointer = pointer;"); + out.println(iii + "}"); + } else if (fname.equals("glNormalPointer")) { + out.println(iii + "if (((type == GL_FLOAT) ||"); + out.println(iii + " (type == GL_BYTE) ||"); + out.println(iii + " (type == GL_SHORT) ||"); + out.println(iii + " (type == GL_FIXED)) &&"); + out.println(iii + " (stride >= 0)) {"); + out.println(iii + indent + "_normalPointer = pointer;"); + out.println(iii + "}"); + } else if (fname.equals("glTexCoordPointer")) { + out.println(iii + "if (((size == 2) ||"); + out.println(iii + " (size == 3) ||"); + out.println(iii + " (size == 4)) &&"); + out.println(iii + " ((type == GL_FLOAT) ||"); + out.println(iii + " (type == GL_BYTE) ||"); + out.println(iii + " (type == GL_SHORT) ||"); + out.println(iii + " (type == GL_FIXED)) &&"); + out.println(iii + " (stride >= 0)) {"); + out.println(iii + indent + "_texCoordPointer = pointer;"); + out.println(iii + "}"); + } else if (fname.equals("glVertexPointer")) { + out.println(iii + "if (((size == 2) ||"); + out.println(iii + " (size == 3) ||"); + out.println(iii + " (size == 4)) &&"); + out.println(iii + " ((type == GL_FLOAT) ||"); + out.println(iii + " (type == GL_BYTE) ||"); + out.println(iii + " (type == GL_SHORT) ||"); + out.println(iii + " (type == GL_FIXED)) &&"); + out.println(iii + " (stride >= 0)) {"); + out.println(iii + indent + "_vertexPointer = pointer;"); + out.println(iii + "}"); + } + } + + // emitBoundsChecks(jfunc, out, iii); + emitFunctionCall(jfunc, out, iii, false); + + boolean isVoid = jfunc.getType().isVoid(); + + if (!isVoid) { + out.println(indent + indent + "return _returnValue;"); + } + out.println(indent + "}"); + } + out.println(); + } + + public static String getJniName(JType jType) { + String jniName = ""; + if (jType.isClass()) { + return "L" + jType.getBaseType() + ";"; + } else if (jType.isArray()) { + jniName = "["; + } + + String baseType = jType.getBaseType(); + if (baseType.equals("int")) { + jniName += "I"; + } else if (baseType.equals("float")) { + jniName += "F"; + } else if (baseType.equals("boolean")) { + jniName += "Z"; + } else if (baseType.equals("short")) { + jniName += "S"; + } else if (baseType.equals("long")) { + jniName += "L"; + } else if (baseType.equals("byte")) { + jniName += "B"; + } + return jniName; + } + + String getJniType(JType jType) { + if (jType.isVoid()) { + return "void"; + } + + String baseType = jType.getBaseType(); + if (jType.isPrimitive()) { + if (baseType.equals("String")) { + return "jstring"; + } else { + return "j" + baseType; + } + } else if (jType.isArray()) { + return "j" + baseType + "Array"; + } else { + return "jobject"; + } + } + + String getJniMangledName(String name) { + name = name.replaceAll("_", "_1"); + name = name.replaceAll(";", "_2"); + name = name.replaceAll("\\[", "_3"); + return name; + } + + public void emitJniCode(JFunc jfunc, PrintStream out) { + CFunc cfunc = jfunc.getCFunc(); + + // Emit comment identifying original C function + // + // Example: + // + // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ + // + out.println("/* " + cfunc.getOriginal() + " */"); + + // Emit JNI signature (name) + // + // Example: + // + // void + // android_glClipPlanef__I_3FI + // + + String outName = "android_" + jfunc.getName(); + boolean isPointerFunc = outName.endsWith("Pointer") && + jfunc.getCFunc().hasPointerArg(); + boolean isVBOPointerFunc = (outName.endsWith("Pointer") || + outName.endsWith("DrawElements")) && + !jfunc.getCFunc().hasPointerArg(); + if (isPointerFunc) { + outName += "Bounds"; + } + + out.print("static "); + out.println(getJniType(jfunc.getType())); + out.print(outName); + + String rsignature = getJniName(jfunc.getType()); + + String signature = ""; + int numArgs = jfunc.getNumArgs(); + for (int i = 0; i < numArgs; i++) { + JType argType = jfunc.getArgType(i); + signature += getJniName(argType); + } + if (isPointerFunc) { + signature += "I"; + } + + // Append signature to function name + String sig = getJniMangledName(signature).replace('.', '_'); + out.print("__" + sig); + outName += "__" + sig; + + signature = signature.replace('.', '/'); + rsignature = rsignature.replace('.', '/'); + + out.println(); + if (rsignature.length() == 0) { + rsignature = "V"; + } + + String s = "{\"" + + jfunc.getName() + + (isPointerFunc ? "Bounds" : "") + + "\", \"(" + signature +")" + + rsignature + + "\", (void *) " + + outName + + " },"; + nativeRegistrations.add(s); + + List<Integer> nonPrimitiveArgs = new ArrayList<Integer>(); + int numBufferArgs = 0; + List<String> bufferArgNames = new ArrayList<String>(); + + // Emit JNI signature (arguments) + // + // Example: + // + // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { + // + out.print(" (JNIEnv *_env, jobject _this"); + for (int i = 0; i < numArgs; i++) { + out.print(", "); + JType argType = jfunc.getArgType(i); + String suffix; + if (!argType.isPrimitive()) { + if (argType.isArray()) { + suffix = "_ref"; + } else { + suffix = "_buf"; + } + nonPrimitiveArgs.add(new Integer(i)); + if (jfunc.getArgType(i).isBuffer()) { + int cIndex = jfunc.getArgCIndex(i); + String cname = cfunc.getArgName(cIndex); + bufferArgNames.add(cname); + numBufferArgs++; + } + } else { + suffix = ""; + } + + out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); + } + if (isPointerFunc) { + out.print(", jint remaining"); + } + out.println(") {"); + + int numArrays = 0; + int numBuffers = 0; + for (int i = 0; i < nonPrimitiveArgs.size(); i++) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + String cname = cfunc.getArgName(cIndex); + if (jfunc.getArgType(idx).isArray()) { + ++numArrays; + } + if (jfunc.getArgType(idx).isBuffer()) { + ++numBuffers; + } + } + + // Emit method body + + // Emit local variable declarations for _exception and _returnValue + // + // Example: + // + // android::gl::ogles_context_t *ctx; + // + // jint _exception; + // GLenum _returnValue; + // + CType returnType = cfunc.getType(); + boolean isVoid = returnType.isVoid(); + + boolean isUnsupported = isUnsupportedFunc(cfunc); + if (isUnsupported) { + out.println(indent + + "_env->ThrowNew(UOEClass,"); + out.println(indent + + " \"" + cfunc.getName() + "\");"); + if (!isVoid) { + String retval = getErrorReturnValue(cfunc); + out.println(indent + "return " + retval + ";"); + } + out.println("}"); + out.println(); + return; + } + + if (mUseContextPointer) { + out.println(indent + + "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); + } + + boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) && + hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs); + // mChecker.getChecks(cfunc.getName()) != null + + // Emit an _exeption variable if there will be error checks + if (emitExceptionCheck) { + out.println(indent + "jint _exception = 0;"); + } + + // Emit a single _array or multiple _XXXArray variables + if (numBufferArgs == 1) { + out.println(indent + "jarray _array = (jarray) 0;"); + } else { + for (int i = 0; i < numBufferArgs; i++) { + out.println(indent + "jarray _" + bufferArgNames.get(i) + + "Array = (jarray) 0;"); + } + } + if (!isVoid) { + String retval = getErrorReturnValue(cfunc); + if (retval != null) { + out.println(indent + returnType.getDeclaration() + + " _returnValue = " + retval + ";"); + } else { + out.println(indent + returnType.getDeclaration() + + " _returnValue;"); + } + } + + // Emit local variable declarations for pointer arguments + // + // Example: + // + // GLfixed *eqn_base; + // GLfixed *eqn; + // + String offset = "offset"; + String remaining = "_remaining"; + if (nonPrimitiveArgs.size() > 0) { + for (int i = 0; i < nonPrimitiveArgs.size(); i++) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + String cname = cfunc.getArgName(cIndex); + + CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); + String decl = type.getDeclaration(); + if (jfunc.getArgType(idx).isArray()) { + out.println(indent + + decl + + (decl.endsWith("*") ? "" : " ") + + jfunc.getArgName(idx) + + "_base = (" + decl + ") 0;"); + } + remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" : + "_" + cname + "Remaining"; + out.println(indent + + "jint " + remaining + ";"); + out.println(indent + + decl + + (decl.endsWith("*") ? "" : " ") + + jfunc.getArgName(idx) + + " = (" + decl + ") 0;"); + } + + out.println(); + } + + String retval = isVoid ? "" : " _returnValue"; + + // Emit 'GetPrimitiveArrayCritical' for arrays + // Emit 'GetPointer' calls for Buffer pointers + int bufArgIdx = 0; + if (nonPrimitiveArgs.size() > 0) { + for (int i = 0; i < nonPrimitiveArgs.size(); i++) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + + String cname = cfunc.getArgName(cIndex); + offset = numArrays <= 1 ? "offset" : + cname + "Offset"; + remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" : + "_" + cname + "Remaining"; + + if (jfunc.getArgType(idx).isArray()) { + out.println(indent + + "if (!" + + cname + + "_ref) {"); + if (emitExceptionCheck) { + out.println(indent + indent + "_exception = 1;"); + } + out.println(indent + " " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + "IAEClass, " + + "\"" + cname + + " == null\");"); + out.println(indent + " goto exit;"); + needsExit = true; + out.println(indent + "}"); + + out.println(indent + "if (" + offset + " < 0) {"); + if (emitExceptionCheck) { + out.println(indent + indent + "_exception = 1;"); + } + out.println(indent + " " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + "IAEClass, " + + "\"" + offset + " < 0\");"); + out.println(indent + " goto exit;"); + needsExit = true; + out.println(indent + "}"); + + out.println(indent + remaining + " = " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->GetArrayLength(" + + (mUseCPlusPlus ? "" : "_env, ") + + cname + "_ref) - " + offset + ";"); + + emitNativeBoundsChecks(cfunc, cname, out, false, + emitExceptionCheck, + offset, remaining, " "); + + out.println(indent + + cname + + "_base = (" + + cfunc.getArgType(cIndex).getDeclaration() + + ")"); + out.println(indent + " " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->GetPrimitiveArrayCritical(" + + (mUseCPlusPlus ? "" : "_env, ") + + jfunc.getArgName(idx) + + "_ref, (jboolean *)0);"); + out.println(indent + + cname + " = " + cname + "_base + " + offset + + ";"); + out.println(); + } else { + String array = numBufferArgs <= 1 ? "_array" : + "_" + bufferArgNames.get(bufArgIdx++) + "Array"; + + boolean nullAllowed = isNullAllowed(cfunc); + if (nullAllowed) { + out.println(indent + "if (" + cname + "_buf) {"); + out.print(indent); + } + + out.println(indent + + cname + + " = (" + + cfunc.getArgType(cIndex).getDeclaration() + + ")getPointer(_env, " + + cname + + "_buf, &" + array + ", &" + remaining + ");"); + + if (nullAllowed) { + out.println(indent + "}"); + } + + emitNativeBoundsChecks(cfunc, cname, out, true, + emitExceptionCheck, + offset, remaining, " "); + } + } + } + + if (!isVoid) { + out.print(indent + "_returnValue = "); + } else { + out.print(indent); + } + String name = cfunc.getName(); + + if (mUseContextPointer) { + name = name.substring(2, name.length()); // Strip off 'gl' prefix + name = name.substring(0, 1).toLowerCase() + + name.substring(1, name.length()); + out.print("ctx->procs."); + } + + out.print(name + (isPointerFunc ? "Bounds" : "") + "("); + + numArgs = cfunc.getNumArgs(); + if (numArgs == 0) { + if (mUseContextPointer) { + out.println("ctx);"); + } else { + out.println(");"); + } + } else { + if (mUseContextPointer) { + out.println("ctx,"); + } else { + out.println(); + } + for (int i = 0; i < numArgs; i++) { + String typecast; + if (i == numArgs - 1 && isVBOPointerFunc) { + typecast = "const GLvoid *"; + } else { + typecast = cfunc.getArgType(i).getDeclaration(); + } + out.print(indent + indent + + "(" + + typecast + + ")" + + cfunc.getArgName(i)); + + if (i == numArgs - 1) { + if (isPointerFunc) { + out.println(","); + out.println(indent + indent + "(GLsizei)remaining"); + } else { + out.println(); + } + } else { + out.println(","); + } + } + out.println(indent + ");"); + } + + if (needsExit) { + out.println(); + out.println("exit:"); + needsExit = false; + } + + bufArgIdx = 0; + if (nonPrimitiveArgs.size() > 0) { + for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { + int idx = nonPrimitiveArgs.get(i).intValue(); + + int cIndex = jfunc.getArgCIndex(idx); + if (jfunc.getArgType(idx).isArray()) { + + // If the argument is 'const', GL will not write to it. + // In this case, we can use the 'JNI_ABORT' flag to avoid + // the need to write back to the Java array + out.println(indent + + "if (" + jfunc.getArgName(idx) + "_base) {"); + out.println(indent + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ReleasePrimitiveArrayCritical(" + + (mUseCPlusPlus ? "" : "_env, ") + + jfunc.getArgName(idx) + "_ref, " + + cfunc.getArgName(cIndex) + + "_base,"); + out.println(indent + indent + indent + + (cfunc.getArgType(cIndex).isConst() ? + "JNI_ABORT" : + "_exception ? JNI_ABORT: 0") + + ");"); + out.println(indent + "}"); + } else if (jfunc.getArgType(idx).isBuffer()) { + String array = numBufferArgs <= 1 ? "_array" : + "_" + bufferArgNames.get(bufArgIdx++) + "Array"; + out.println(indent + "if (" + array + ") {"); + out.println(indent + indent + + "releasePointer(_env, " + array + ", " + + cfunc.getArgName(cIndex) + + ", " + + (cfunc.getArgType(cIndex).isConst() ? + "JNI_FALSE" : "_exception ? JNI_FALSE : JNI_TRUE") + + ");"); + out.println(indent + "}"); + } + } + } + + if (!isVoid) { + out.println(indent + "return _returnValue;"); + } + + out.println("}"); + out.println(); + } + + public void addNativeRegistration(String s) { + nativeRegistrations.add(s); + } + + public void emitNativeRegistration() { + mCStream.println("static const char *classPathName = \"" + + mClassPathName + + "\";"); + mCStream.println(); + + mCStream.println("static JNINativeMethod methods[] = {"); + + mCStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); + + Iterator<String> i = nativeRegistrations.iterator(); + while (i.hasNext()) { + mCStream.println(i.next()); + } + + mCStream.println("};"); + mCStream.println(); + + + mCStream.println("int register_com_google_android_gles_jni_GLImpl(JNIEnv *_env)"); + mCStream.println("{"); + mCStream.println(indent + + "int err;"); + + mCStream.println(indent + + "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); + + mCStream.println(indent + "return err;"); + mCStream.println("}"); + } +} diff --git a/opengl/tools/glgen/src/ParameterChecker.java b/opengl/tools/glgen/src/ParameterChecker.java new file mode 100644 index 0000000..df26acd --- /dev/null +++ b/opengl/tools/glgen/src/ParameterChecker.java @@ -0,0 +1,28 @@ + +import java.io.BufferedReader; +import java.util.HashMap; + +public class ParameterChecker { + + HashMap<String,String[]> map = new HashMap<String,String[]>(); + + public ParameterChecker(BufferedReader reader) throws Exception { + String s; + while ((s = reader.readLine()) != null) { + String[] tokens = s.split("\\s"); + map.put(tokens[0], tokens); + } + } + + public String[] getChecks(String functionName) { + String[] checks = map.get(functionName); + if (checks == null && + (functionName.endsWith("fv") || + functionName.endsWith("xv") || + functionName.endsWith("iv"))) { + functionName = functionName.substring(0, functionName.length() - 2); + checks = map.get(functionName); + } + return checks; + } +} |