replicant-frameworks_native/opengl/tools/glgen/src/JniCodeEmitter.java
Jack Palevich 66089a33ea Implement Matrix Palette extension.
Adds support for formerly-unimplemented methods:

glCurrentPaletteMatrixOES
glLoadPaletteFromModelViewMatrixOES
glMatrixIndexPointerOES
glWeightPointerOES

The bulk of the changes are related to implementing the two PointerOES
methods, which are implemented pretty much the same way as the existing
Pointer methods were implemented.

This change also changes the way glPointSizePointerOES is implemented,
making it act like all the other Pointer methods. (Previously it was
not handling non-direct-buffer arguments correctly.)

Fixes bug 2308625 "Support matrix palette skinning
in JSR239 and related APIs"

Also updated GLLogWraper to fix two bugs in GLLogWrapper that were
discovered while testing matrix palette skinning support:

a) Handle trying to print the contents of null-but-enabled buffers.
(It's not legal to draw with null-but-enabled buffers, and
in fact some OpenGL drivers will crash if you try to render in this
state, but there's no reason the GLLogWrapper should crash while trying
to debug this situation.

b) Don't read off the end of a vertex buffer with non-zero position when
printing the entire contents of the vertex buffer. Now we only print from
the current position to the end of the buffer.
2009-12-08 15:43:51 +08:00

1141 lines
44 KiB
Java

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
public class JniCodeEmitter {
static final boolean mUseCPlusPlus = true;
protected boolean mUseContextPointer = true;
protected boolean mUseStaticMethods = false;
protected String mClassPathName;
protected ParameterChecker mChecker;
protected List<String> nativeRegistrations = new ArrayList<String>();
boolean needsExit;
protected static String indent = " ";
HashSet<String> mFunctionsEmitted = new HashSet<String>();
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";
} else if (baseType.equals("String")) {
jniName += "Ljava/lang/String;";
} else if (baseType.equals("void")) {
// nothing.
} else {
throw new RuntimeException("Uknown primitive basetype " + baseType);
}
return jniName;
}
public void emitCode(CFunc cfunc, String original,
PrintStream javaInterfaceStream,
PrintStream javaImplStream,
PrintStream cStream) {
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, javaImplStream);
emitJavaCode(jfunc, javaImplStream);
}
if (javaInterfaceStream != null) {
emitJavaInterfaceCode(jfunc, javaInterfaceStream);
}
if (!duplicate) {
emitJniCode(jfunc, cStream);
}
}
jfunc = JFunc.convert(cfunc, false);
signature = jfunc.toString();
duplicate = false;
if (mFunctionsEmitted.contains(signature)) {
duplicate = true;
} else {
mFunctionsEmitted.add(signature);
}
if (!duplicate) {
emitNativeDeclaration(jfunc, javaImplStream);
}
if (javaInterfaceStream != null) {
emitJavaInterfaceCode(jfunc, javaInterfaceStream);
}
if (!duplicate) {
emitJavaCode(jfunc, javaImplStream);
emitJniCode(jfunc, cStream);
}
}
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);
}
boolean isPointerFunc(JFunc jfunc) {
String name = jfunc.getName();
return (name.endsWith("Pointer") || name.endsWith("PointerOES"))
&& jfunc.getCFunc().hasPointerArg();
}
void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray) {
boolean isVoid = jfunc.getType().isVoid();
boolean isPointerFunc = isPointerFunc(jfunc);
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) {
String[] checks = mChecker.getChecks(cfunc.getName());
boolean lastWasIfcheck = false;
int index = 1;
if (checks != null) {
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 = isPointerFunc(jfunc);
if (!nativeDecl && !interfaceDecl && !isPointerFunc) {
// If it's not a pointer function, we've already emitted it
// with nativeDecl == true
return;
}
String maybeStatic = mUseStaticMethods ? "static " : "";
if (isPointerFunc) {
out.println(indent +
(nativeDecl ? "private " + maybeStatic +"native " :
(interfaceDecl ? "" : "public ") + maybeStatic) +
jfunc.getType() + " " +
jfunc.getName() +
(nativeDecl ? "Bounds" : "") +
"(");
} else {
out.println(indent +
(nativeDecl ? "public " + maybeStatic +"native " :
(interfaceDecl ? "" : "public ") + maybeStatic) +
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;
// emitBoundsChecks(jfunc, out, iii);
emitFunctionCall(jfunc, out, iii, false);
// Set the pointer after we call the native code, so that if
// the native code throws an exception we don't modify the
// pointer. We assume that the native code is written so that
// if an exception is thrown, then the underlying glXXXPointer
// function will not have been called.
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 + "}");
} else if (fname.equals("glPointSizePointerOES")) {
out.println(iii + "if (((type == GL_FLOAT) ||");
out.println(iii + " (type == GL_FIXED)) &&");
out.println(iii + " (stride >= 0)) {");
out.println(iii + indent + "_pointSizePointerOES = pointer;");
out.println(iii + "}");
} else if (fname.equals("glMatrixIndexPointerOES")) {
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 + "_matrixIndexPointerOES = pointer;");
out.println(iii + "}");
} else if (fname.equals("glWeightPointer")) {
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 + "_weightPointerOES = pointer;");
out.println(iii + "}");
}
}
boolean isVoid = jfunc.getType().isVoid();
if (!isVoid) {
out.println(indent + indent + "return _returnValue;");
}
out.println(indent + "}");
}
out.println();
}
public void addNativeRegistration(String s) {
nativeRegistrations.add(s);
}
public void emitNativeRegistration(String registrationFunctionName,
PrintStream cStream) {
cStream.println("static const char *classPathName = \"" +
mClassPathName +
"\";");
cStream.println();
cStream.println("static JNINativeMethod methods[] = {");
cStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },");
Iterator<String> i = nativeRegistrations.iterator();
while (i.hasNext()) {
cStream.println(i.next());
}
cStream.println("};");
cStream.println();
cStream.println("int " + registrationFunctionName + "(JNIEnv *_env)");
cStream.println("{");
cStream.println(indent +
"int err;");
cStream.println(indent +
"err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));");
cStream.println(indent + "return err;");
cStream.println("}");
}
public JniCodeEmitter() {
super();
}
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 = isPointerFunc(jfunc);
boolean isVBOPointerFunc = (outName.endsWith("Pointer") ||
outName.endsWith("PointerOES") ||
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('.', '_').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>();
List<Integer> stringArgs = 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 = "";
}
if (argType.isString()) {
stringArgs.add(new Integer(i));
}
out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix);
}
if (isPointerFunc) {
out.print(", jint remaining");
}
out.println(") {");
int numArrays = 0;
int numBuffers = 0;
int numStrings = 0;
for (int i = 0; i < nonPrimitiveArgs.size(); i++) {
int idx = nonPrimitiveArgs.get(i).intValue();
JType argType = jfunc.getArgType(idx);
if (argType.isArray()) {
++numArrays;
}
if (argType.isBuffer()) {
++numBuffers;
}
if (argType.isString()) {
++numStrings;
}
}
// 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 initializeReturnValue = stringArgs.size() > 0;
boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0 || numStrings > 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 if (initializeReturnValue) {
out.println(indent + returnType.getDeclaration() +
" _returnValue = 0;");
} 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 + numBuffers) <= 1) ? "_remaining" :
"_" + cname + "Remaining";
out.println(indent +
"jint " + remaining + ";");
out.println(indent +
decl +
(decl.endsWith("*") ? "" : " ") +
jfunc.getArgName(idx) +
" = (" + decl + ") 0;");
}
out.println();
}
// Emit local variable declaration for strings
if (stringArgs.size() > 0) {
for (int i = 0; i < stringArgs.size(); i++) {
int idx = stringArgs.get(i).intValue();
int cIndex = jfunc.getArgCIndex(idx);
String cname = cfunc.getArgName(cIndex);
out.println(indent + "const char* _native" + cname + " = 0;");
}
out.println();
}
// Null pointer checks and GetStringUTFChars
if (stringArgs.size() > 0) {
for (int i = 0; i < stringArgs.size(); i++) {
int idx = stringArgs.get(i).intValue();
int cIndex = jfunc.getArgCIndex(idx);
String cname = cfunc.getArgName(cIndex);
CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
String decl = type.getDeclaration();
out.println(indent + "if (!" + cname + ") {");
out.println(indent + " _env->ThrowNew(IAEClass, \"" + cname + " == null\");");
out.println(indent + " goto exit;");
needsExit = true;
out.println(indent + "}");
out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);");
}
out.println();
}
// 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 + 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) || isPointerFunc;
if (nullAllowed) {
out.println(indent + "if (" + cname + "_buf) {");
out.print(indent);
}
if (isPointerFunc) {
out.println(indent +
cname +
" = (" +
cfunc.getArgType(cIndex).getDeclaration() +
") getDirectBufferPointer(_env, " +
cname + "_buf);");
String iii = " ";
out.println(iii + indent + "if ( ! " + cname + " ) {");
out.println(iii + iii + indent + "return;");
out.println(iii + indent + "}");
} else {
out.println(indent +
cname +
" = (" +
cfunc.getArgType(cIndex).getDeclaration() +
")getPointer(_env, " +
cname +
"_buf, &" + array + ", &" + remaining +
");");
}
emitNativeBoundsChecks(cfunc, cname, out, true,
emitExceptionCheck,
offset, remaining, nullAllowed ? " " : " ");
if (nullAllowed) {
out.println(indent + "}");
}
}
}
}
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 +
")");
if (cfunc.getArgType(i).isConstCharPointer()) {
out.print("_native");
}
out.print(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()) {
if (! isPointerFunc) {
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 + "}");
}
}
}
}
// Emit local variable declaration for strings
if (stringArgs.size() > 0) {
for (int i = 0; i < stringArgs.size(); i++) {
int idx = stringArgs.get(i).intValue();
int cIndex = jfunc.getArgCIndex(idx);
String cname = cfunc.getArgName(cIndex);
out.println(indent + "if (_native" + cname + ") {");
out.println(indent + " _env->ReleaseStringUTFChars(" + cname + ", _native" + cname + ");");
out.println(indent + "}");
}
out.println();
}
if (!isVoid) {
out.println(indent + "return _returnValue;");
}
out.println("}");
out.println();
}
}