66089a33ea
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.
1141 lines
44 KiB
Java
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();
|
|
}
|
|
|
|
}
|