summaryrefslogtreecommitdiffstats
path: root/opengl/tools/glgen/src/JniCodeEmitter.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
commite09fd9e819c23dc90bca68375645e15544861330 (patch)
tree9a9fdadd1301625f875a3c126c986c79e3363ac4 /opengl/tools/glgen/src/JniCodeEmitter.java
parent7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407 (diff)
downloadframeworks_native-e09fd9e819c23dc90bca68375645e15544861330.zip
frameworks_native-e09fd9e819c23dc90bca68375645e15544861330.tar.gz
frameworks_native-e09fd9e819c23dc90bca68375645e15544861330.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'opengl/tools/glgen/src/JniCodeEmitter.java')
-rw-r--r--opengl/tools/glgen/src/JniCodeEmitter.java1086
1 files changed, 1086 insertions, 0 deletions
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("}");
+ }
+}