summaryrefslogtreecommitdiffstats
path: root/opengl/tools/glgen/src
diff options
context:
space:
mode:
Diffstat (limited to 'opengl/tools/glgen/src')
-rw-r--r--opengl/tools/glgen/src/CFunc.java155
-rw-r--r--opengl/tools/glgen/src/CType.java85
-rw-r--r--opengl/tools/glgen/src/CodeEmitter.java8
-rw-r--r--opengl/tools/glgen/src/GenerateGL.java164
-rw-r--r--opengl/tools/glgen/src/JFunc.java148
-rw-r--r--opengl/tools/glgen/src/JType.java139
-rw-r--r--opengl/tools/glgen/src/JniCodeEmitter.java1086
-rw-r--r--opengl/tools/glgen/src/ParameterChecker.java28
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;
+ }
+}