From edbf3b6af777b721cd2a1ef461947e51e88241e1 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:31:44 -0800 Subject: auto import from //depot/cupcake/@135843 --- opengl/tools/glgen/src/CFunc.java | 155 ++++ opengl/tools/glgen/src/CType.java | 85 ++ opengl/tools/glgen/src/CodeEmitter.java | 8 + opengl/tools/glgen/src/GenerateGL.java | 164 ++++ opengl/tools/glgen/src/JFunc.java | 148 ++++ opengl/tools/glgen/src/JType.java | 139 ++++ opengl/tools/glgen/src/JniCodeEmitter.java | 1086 ++++++++++++++++++++++++++ opengl/tools/glgen/src/ParameterChecker.java | 28 + 8 files changed, 1813 insertions(+) create mode 100644 opengl/tools/glgen/src/CFunc.java create mode 100644 opengl/tools/glgen/src/CType.java create mode 100644 opengl/tools/glgen/src/CodeEmitter.java create mode 100644 opengl/tools/glgen/src/GenerateGL.java create mode 100644 opengl/tools/glgen/src/JFunc.java create mode 100644 opengl/tools/glgen/src/JType.java create mode 100644 opengl/tools/glgen/src/JniCodeEmitter.java create mode 100644 opengl/tools/glgen/src/ParameterChecker.java (limited to 'opengl/tools/glgen/src') 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 argNames = new ArrayList(); + List argTypes = new ArrayList(); + + 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 argNames = new ArrayList(); + List argTypes = new ArrayList(); + List argCIndices = new ArrayList(); + + boolean hasBufferArg = false; + boolean hasTypedBufferArg = false; + ArrayList bufferArgNames = new ArrayList(); + + 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 typeMapping = new HashMap(); + static HashMap arrayTypeMapping = new HashMap(); + + 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. + * + *

The Java interface will have Buffer and array variants for functions that + * have a typed pointer argument. The array variant will convert a single " *data" + * argument to a pair of arguments "[] 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 nativeRegistrations = new ArrayList(); + + boolean needsExit; + + static String indent = " "; + + HashSet mFunctionsEmitted = new HashSet(); + + /** + * @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_", 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 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 func(args); + * + * if !nativeDecl: + * if interfaceDecl: public func(args); + * if !interfaceDecl: public 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 nonPrimitiveArgs = new ArrayList(); + int numBufferArgs = 0; + List bufferArgNames = new ArrayList(); + + // 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 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 map = new HashMap(); + + 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; + } +} -- cgit v1.1