From 66a42db8cbfba902f72f0ace5ac448ef4bfd3951 Mon Sep 17 00:00:00 2001 From: Thomas Tafertshofer Date: Fri, 15 Jun 2012 16:22:43 -0700 Subject: improve glgen tool to support EGL1.4 - added EGL1.4 bindings generation - fixed bugs in GLES bindings Bug: 6709865 Change-Id: I04ac63f652e1968a51eb833f47e00336ea449980 --- opengl/tools/glgen/src/CFunc.java | 8 + opengl/tools/glgen/src/CType.java | 10 + opengl/tools/glgen/src/EGLCodeEmitter.java | 58 ++++ opengl/tools/glgen/src/GenerateEGL.java | 109 ++++++ opengl/tools/glgen/src/JType.java | 30 +- opengl/tools/glgen/src/JniCodeEmitter.java | 513 +++++++++++++++++++++-------- 6 files changed, 581 insertions(+), 147 deletions(-) create mode 100644 opengl/tools/glgen/src/EGLCodeEmitter.java create mode 100644 opengl/tools/glgen/src/GenerateEGL.java (limited to 'opengl/tools/glgen/src') diff --git a/opengl/tools/glgen/src/CFunc.java b/opengl/tools/glgen/src/CFunc.java index 4847694..a192c00 100644 --- a/opengl/tools/glgen/src/CFunc.java +++ b/opengl/tools/glgen/src/CFunc.java @@ -28,6 +28,7 @@ public class CFunc { boolean hasPointerArg = false; boolean hasTypedPointerArg = false; + boolean hasEGLHandleArg = false; public CFunc(String original) { this.original = original; @@ -63,6 +64,9 @@ public class CFunc { if (argType.isTypedPointer()) { hasTypedPointerArg = true; } + if (argType.isEGLHandle()) { + hasEGLHandleArg = true; + } } public int getNumArgs() { @@ -95,6 +99,10 @@ public class CFunc { return hasTypedPointerArg; } + public boolean hasEGLHandleArg() { + return hasEGLHandleArg; + } + @Override public String toString() { String s = "Function " + fname + " returns " + ftype + ": "; diff --git a/opengl/tools/glgen/src/CType.java b/opengl/tools/glgen/src/CType.java index e0f0ca6..92950ea 100644 --- a/opengl/tools/glgen/src/CType.java +++ b/opengl/tools/glgen/src/CType.java @@ -53,6 +53,16 @@ public class CType { return isPointer; } + public boolean isEGLHandle() { + if(baseType.equals("EGLContext") + || baseType.equals("EGLConfig") + || baseType.equals("EGLSurface") + || baseType.equals("EGLDisplay")) { + return true; + } + return false; + } + boolean isVoid() { String baseType = getBaseType(); return baseType.equals("GLvoid") || diff --git a/opengl/tools/glgen/src/EGLCodeEmitter.java b/opengl/tools/glgen/src/EGLCodeEmitter.java new file mode 100644 index 0000000..1691b65 --- /dev/null +++ b/opengl/tools/glgen/src/EGLCodeEmitter.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.PrintStream; + +/** + * Emits a Java interface and Java & C implementation for a C function. + * + *

The Java interface will have Buffer and array variants for functions that + * have a typed pointer argument. The array variant will convert a single " *data" + * argument to a pair of arguments "[] data, int offset". + */ +public class EGLCodeEmitter extends JniCodeEmitter { + + PrintStream mJavaImplStream; + PrintStream mCStream; + + PrintStream mJavaInterfaceStream; + + /** + */ + public EGLCodeEmitter(String classPathName, + ParameterChecker checker, + PrintStream javaImplStream, + PrintStream cStream) { + mClassPathName = classPathName; + mChecker = checker; + + mJavaImplStream = javaImplStream; + mCStream = cStream; + mUseContextPointer = false; + mUseStaticMethods = true; + mUseSimpleMethodNames = true; + mUseHideCommentForAPI = true; + } + + public void emitCode(CFunc cfunc, String original) { + emitCode(cfunc, original, null, mJavaImplStream, + mCStream); + } + + public void emitNativeRegistration(String nativeRegistrationName) { + emitNativeRegistration(nativeRegistrationName, mCStream); + } +} diff --git a/opengl/tools/glgen/src/GenerateEGL.java b/opengl/tools/glgen/src/GenerateEGL.java new file mode 100644 index 0000000..aaa748c --- /dev/null +++ b/opengl/tools/glgen/src/GenerateEGL.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; + +public class GenerateEGL { + + private static void copy(String filename, PrintStream out) throws IOException { + BufferedReader br = new BufferedReader(new FileReader(filename)); + String s; + while ((s = br.readLine()) != null) { + out.println(s); + } + } + + private static void emit(EGLCodeEmitter emitter, + BufferedReader specReader, + PrintStream glStream, + PrintStream cStream) throws Exception { + String s = null; + while ((s = specReader.readLine()) != null) { + if (s.trim().startsWith("//")) { + continue; + } + + CFunc cfunc = CFunc.parseCFunc(s); + + String fname = cfunc.getName(); + String stubRoot = "stubs/egl/" + fname; + String javaPath = stubRoot + ".java"; + File f = new File(javaPath); + if (f.exists()) { + System.out.println("Special-casing function " + fname); + copy(javaPath, glStream); + copy(stubRoot + ".cpp", cStream); + + // Register native function names + // This should be improved to require fewer discrete files + String filename = stubRoot + ".nativeReg"; + BufferedReader br = + new BufferedReader(new FileReader(filename)); + String nfunc; + while ((nfunc = br.readLine()) != null) { + emitter.addNativeRegistration(nfunc); + } + } else { + emitter.emitCode(cfunc, s); + } + } + } + + public static void main(String[] args) throws Exception { + int aidx = 0; + while ((aidx < args.length) && (args[aidx].charAt(0) == '-')) { + switch (args[aidx].charAt(1)) { + default: + System.err.println("Unknown flag: " + args[aidx]); + System.exit(1); + } + + aidx++; + } + + BufferedReader checksReader = + new BufferedReader(new FileReader("specs/egl/checks.spec")); + ParameterChecker checker = new ParameterChecker(checksReader); + + + BufferedReader specReader = + new BufferedReader(new FileReader("specs/egl/EGL14.spec")); + + String egljFilename = "android/opengl/EGL14.java"; + String eglcFilename = "android_opengl_EGL14.cpp"; + PrintStream egljStream = + new PrintStream(new FileOutputStream("out/" + egljFilename)); + PrintStream eglcStream = + new PrintStream(new FileOutputStream("out/" + eglcFilename)); + egljStream.println("/*"); + eglcStream.println("/*"); + copy("stubs/egl/EGL14Header.java-if", egljStream); + copy("stubs/egl/EGL14cHeader.cpp", eglcStream); + EGLCodeEmitter emitter = new EGLCodeEmitter( + "android/opengl/EGL14", + checker, egljStream, eglcStream); + emit(emitter, specReader, egljStream, eglcStream); + emitter.emitNativeRegistration("register_android_opengl_jni_EGL14"); + egljStream.println("}"); + egljStream.close(); + eglcStream.close(); + } +} diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java index deb2f01..3f7cb73 100644 --- a/opengl/tools/glgen/src/JType.java +++ b/opengl/tools/glgen/src/JType.java @@ -48,6 +48,22 @@ public class JType { typeMapping.put(new CType("char", true, true), new JType("String", false, false)); typeMapping.put(new CType("int"), new JType("int")); + // EGL primitive types + typeMapping.put(new CType("EGLint"), new JType("int")); + typeMapping.put(new CType("EGLBoolean"), new JType("boolean")); + typeMapping.put(new CType("EGLenum"), new JType("int")); + typeMapping.put(new CType("EGLNativePixmapType"), new JType("int")); + typeMapping.put(new CType("EGLNativeWindowType"), new JType("int")); + typeMapping.put(new CType("EGLNativeDisplayType"), new JType("int")); + typeMapping.put(new CType("EGLClientBuffer"), new JType("int")); + + // EGL nonprimitive types + typeMapping.put(new CType("EGLConfig"), new JType("EGLConfig", true, false)); + typeMapping.put(new CType("EGLContext"), new JType("EGLContext", true, false)); + typeMapping.put(new CType("EGLDisplay"), new JType("EGLDisplay", true, false)); + typeMapping.put(new CType("EGLSurface"), new JType("EGLSurface", true, false)); + + // Untyped pointers map to untyped Buffers typeMapping.put(new CType("GLvoid", true, true), new JType("java.nio.Buffer", true, false)); @@ -88,7 +104,7 @@ public class JType { arrayTypeMapping.put(new CType("char", false, true), new JType("byte", false, true)); arrayTypeMapping.put(new CType("GLboolean", false, true), - new JType("boolean", false, true)); + new JType("boolean", false, true)); arrayTypeMapping.put(new CType("GLenum", false, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLfixed", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLfixed", false, true), new JType("int", false, true)); @@ -103,6 +119,13 @@ public class JType { arrayTypeMapping.put(new CType("GLuint", true, true), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLintptr"), new JType("int", false, true)); arrayTypeMapping.put(new CType("GLsizeiptr"), new JType("int", false, true)); + + //EGL typed pointers map to arrays + offsets + arrayTypeMapping.put(new CType("EGLint", false, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("EGLint", true, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("EGLConfig", false, true), new JType("EGLConfig", true, true)); + arrayTypeMapping.put(new CType("EGLConfig", true, true), new JType("EGLConfig", true, true)); + } public JType() { @@ -158,6 +181,11 @@ public class JType { (baseType.indexOf("Buffer") != -1); } + public boolean isEGLHandle() { + return !isPrimitive() && + (baseType.startsWith("EGL")); + } + public static JType convert(CType ctype, boolean useArray) { JType javaType = null; if (useArray) { diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java index 9fa2b74..af98889 100644 --- a/opengl/tools/glgen/src/JniCodeEmitter.java +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -25,6 +25,8 @@ public class JniCodeEmitter { static final boolean mUseCPlusPlus = true; protected boolean mUseContextPointer = true; protected boolean mUseStaticMethods = false; + protected boolean mUseSimpleMethodNames = false; + protected boolean mUseHideCommentForAPI = false; protected String mClassPathName; protected ParameterChecker mChecker; protected List nativeRegistrations = new ArrayList(); @@ -34,7 +36,9 @@ public class JniCodeEmitter { public static String getJniName(JType jType) { String jniName = ""; - if (jType.isClass()) { + if (jType.isEGLHandle()) { + return (jType.isArray() ? "[" : "" ) + "Landroid/opengl/" + jType.getBaseType() + ";"; + } else if (jType.isClass()) { return "L" + jType.getBaseType() + ";"; } else if (jType.isArray()) { jniName = "["; @@ -63,7 +67,6 @@ public class JniCodeEmitter { return jniName; } - public void emitCode(CFunc cfunc, String original, PrintStream javaInterfaceStream, PrintStream javaImplStream, @@ -96,6 +99,10 @@ public class JniCodeEmitter { if (!duplicate) { emitJniCode(jfunc, cStream); } + // Don't create IOBuffer versions of the EGL functions + if (cfunc.hasEGLHandleArg()) { + return; + } } jfunc = JFunc.convert(cfunc, false); @@ -121,8 +128,13 @@ public class JniCodeEmitter { } public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { - out.println(" // C function " + jfunc.getCFunc().getOriginal()); - out.println(); + if (mUseHideCommentForAPI) { + out.println(" /* @hide C function " + jfunc.getCFunc().getOriginal() + " */"); + out.println(); + } else { + out.println(" // C function " + jfunc.getCFunc().getOriginal()); + out.println(); + } emitFunction(jfunc, out, true, false); } @@ -197,15 +209,17 @@ public class JniCodeEmitter { out.println(iii + "}"); out.println(iii + "if (" + remaining + " < _needed) {"); - if (emitExceptionCheck) { - out.println(iii + indent + "_exception = 1;"); - } - out.println(iii + indent + "jniThrowException(_env, " + - "\"java/lang/IllegalArgumentException\", " + - "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < needed\");"); + out.println(iii + indent + "_exception = 1;"); + out.println(iii + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(iii + indent + + "_exceptionMessage = \"" + + (isBuffer ? "remaining()" : "length - " + offset) + + " < needed\";"); out.println(iii + indent + "goto exit;"); - needsExit = true; out.println(iii + "}"); + + needsExit = true; } boolean isNullAllowed(CFunc cfunc) { @@ -213,28 +227,70 @@ public class JniCodeEmitter { 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("requires")) { - index += 2; - } else if (checks[index].equals("nullAllowed")) { + if (checks[index].equals("nullAllowed")) { + return true; + } else { + index = skipOneCheck(checks, index); + } + } + } + return false; + } + + boolean hasCheckTest(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].startsWith("check")) { + return true; + } else { + index = skipOneCheck(checks, index); + } + } + } + return false; + } + + boolean hasIfTest(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].startsWith("ifcheck")) { return true; } else { - System.out.println("Error: unknown keyword \"" + - checks[index] + "\""); - System.exit(0); + index = skipOneCheck(checks, index); } } } return false; } + int skipOneCheck(String[] checks, int index) { + if (checks[index].equals("return")) { + index += 2; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].startsWith("sentinel")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("unsupported")) { + index += 1; + } else if (checks[index].equals("requires")) { + index += 2; + } else if (checks[index].equals("nullAllowed")) { + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + + return index; + } + String getErrorReturnValue(CFunc cfunc) { CType returnType = cfunc.getType(); boolean isVoid = returnType.isVoid(); @@ -242,6 +298,10 @@ public class JniCodeEmitter { return null; } + if (returnType.getBaseType().startsWith("EGL")) { + return "(" + returnType.getDeclaration() + ") 0"; + } + String[] checks = mChecker.getChecks(cfunc.getName()); int index = 1; @@ -249,20 +309,8 @@ public class JniCodeEmitter { 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("requires")) { - index += 2; - } else if (checks[index].equals("nullAllowed")) { - index += 1; } else { - System.out.println("Error: unknown keyword \"" + - checks[index] + "\""); - System.exit(0); + index = skipOneCheck(checks, index); } } } @@ -277,20 +325,8 @@ public class JniCodeEmitter { while (index < checks.length) { if (checks[index].equals("unsupported")) { return true; - } else if (checks[index].equals("requires")) { - index += 2; - } 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); + index = skipOneCheck(checks, index); } } } @@ -302,22 +338,10 @@ public class JniCodeEmitter { int index = 1; if (checks != null) { while (index < checks.length) { - if (checks[index].equals("unsupported")) { - index += 1; - } else if (checks[index].equals("requires")) { + if (checks[index].equals("requires")) { return checks[index+1]; - } 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); + index = skipOneCheck(checks, index); } } } @@ -345,9 +369,7 @@ public class JniCodeEmitter { continue; } out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {"); - if (emitExceptionCheck) { - out.println(iii + indent + "_exception = 1;"); - } + out.println(iii + indent + "_exception = 1;"); String exceptionClassName = "java/lang/IllegalArgumentException"; // If the "check" keyword was of the form // "check_", use the class name in the @@ -361,14 +383,19 @@ public class JniCodeEmitter { throw new RuntimeException("unknown exception abbreviation: " + abbr); } } - out.println(iii + indent + "jniThrowException(_env, " + - "\"" + exceptionClassName + "\", " + - "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < " + checks[index + 2] + "\");"); + out.println(iii + indent + + "_exceptionType = \""+exceptionClassName+"\";"); + out.println(iii + indent + + "_exceptionMessage = \"" + + (isBuffer ? "remaining()" : "length - " + + offset) + " < " + checks[index + 2] + + " < needed\";"); out.println(iii + indent + "goto exit;"); - needsExit = true; out.println(iii + "}"); + needsExit = true; + index += 3; } else if (checks[index].equals("ifcheck")) { String[] matches = checks[index + 4].split(","); @@ -388,21 +415,8 @@ public class JniCodeEmitter { 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("requires")) { - // ignore - index += 2; - } else if (checks[index].equals("nullAllowed")) { - // ignore - index += 1; } else { - System.out.println("Error: unknown keyword \"" + checks[index] + "\""); - System.exit(0); + index = skipOneCheck(checks, index); } } } @@ -412,6 +426,69 @@ public class JniCodeEmitter { } } + void emitSentinelCheck(CFunc cfunc, String cname, PrintStream out, + boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) { + + String[] checks = mChecker.getChecks(cfunc.getName()); + + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].startsWith("sentinel")) { + if (cname != null && !cname.equals(checks[index + 1])) { + index += 3; + continue; + } + + out.println(iii + cname + "_sentinel = false;"); + out.println(iii + "for (int i = " + remaining + + " - 1; i >= 0; i--) {"); + out.println(iii + indent + "if (" + cname + + "[i] == " + checks[index + 2] + "){"); + out.println(iii + indent + indent + + cname + "_sentinel = true;"); + out.println(iii + indent + indent + "break;"); + out.println(iii + indent + "}"); + out.println(iii + "}"); + out.println(iii + + "if (" + cname + "_sentinel == false) {"); + out.println(iii + indent + "_exception = 1;"); + out.println(iii + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(iii + indent + "_exceptionMessage = \"" + cname + + " must contain " + checks[index + 2] + "!\";"); + out.println(iii + indent + "goto exit;"); + out.println(iii + "}"); + + needsExit = true; + index += 3; + } else { + index = skipOneCheck(checks, index); + } + } + } + } + + void emitLocalVariablesForSentinel(CFunc cfunc, PrintStream out) { + + String[] checks = mChecker.getChecks(cfunc.getName()); + + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].startsWith("sentinel")) { + String cname = checks[index + 1]; + out.println(indent + "bool " + cname + "_sentinel = false;"); + + index += 3; + + } else { + index = skipOneCheck(checks, index); + } + } + } + } + boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List nonPrimitiveArgs) { if (nonPrimitiveArgs.size() > 0) { for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { @@ -638,7 +715,7 @@ public class JniCodeEmitter { return "j" + baseType; } } else if (jType.isArray()) { - return "j" + baseType + "Array"; + return jType.isClass() ? "jobjectArray" : "j" + baseType + "Array"; } else { return "jobject"; } @@ -698,8 +775,10 @@ public class JniCodeEmitter { // Append signature to function name String sig = getJniMangledName(signature).replace('.', '_').replace('/', '_'); - out.print("__" + sig); - outName += "__" + sig; + if (!mUseSimpleMethodNames) { + out.print("__" + sig); + outName += "__" + sig; + } signature = signature.replace('.', '/'); rsignature = rsignature.replace('.', '/'); @@ -734,11 +813,11 @@ public class JniCodeEmitter { for (int i = 0; i < numArgs; i++) { out.print(", "); JType argType = jfunc.getArgType(i); - String suffix; + String suffix = ""; if (!argType.isPrimitive()) { if (argType.isArray()) { suffix = "_ref"; - } else { + } else if (argType.isBuffer()) { suffix = "_buf"; } nonPrimitiveArgs.add(new Integer(i)); @@ -748,9 +827,8 @@ public class JniCodeEmitter { bufferArgNames.add(cname); numBufferArgs++; } - } else { - suffix = ""; } + if (argType.isString()) { stringArgs.add(new Integer(i)); } @@ -801,7 +879,14 @@ public class JniCodeEmitter { " \"" + cfunc.getName() + "\");"); if (!isVoid) { String retval = getErrorReturnValue(cfunc); - out.println(indent + "return " + retval + ";"); + if (cfunc.getType().isEGLHandle()) { + String baseType = cfunc.getType().getBaseType().toLowerCase(); + out.println(indent + + "return toEGLHandle(_env, " + baseType + "Class, " + + baseType + "Constructor, " + retval + ");"); + } else { + out.println(indent + "return " + retval + ";"); + } } out.println("}"); out.println(); @@ -820,7 +905,14 @@ public class JniCodeEmitter { out.println(indent + indent + " return;"); } else { String retval = getErrorReturnValue(cfunc); - out.println(indent + indent + " return " + retval + ";"); + if (cfunc.getType().isEGLHandle()) { + String baseType = cfunc.getType().getBaseType().toLowerCase(); + out.println(indent + + "return toEGLHandle(_env, " + baseType + "Class, " + + baseType + "Constructor, " + retval + ");"); + } else { + out.println(indent + "return " + retval + ";"); + } } out.println(indent + "}"); } @@ -830,14 +922,18 @@ public class JniCodeEmitter { } boolean initializeReturnValue = stringArgs.size() > 0; - - boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0 || numStrings > 0) && - hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs); + boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) + && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) + || (cfunc.hasPointerArg() && numArrays > 0)) + || hasCheckTest(cfunc) + || hasIfTest(cfunc)) + || (stringArgs.size() > 0); // mChecker.getChecks(cfunc.getName()) != null - // Emit an _exeption variable if there will be error checks if (emitExceptionCheck) { out.println(indent + "jint _exception = 0;"); + out.println(indent + "const char * _exceptionType;"); + out.println(indent + "const char * _exceptionMessage;"); } // Emit a single _array or multiple _XXXArray variables @@ -856,13 +952,49 @@ public class JniCodeEmitter { " _returnValue = " + retval + ";"); } else if (initializeReturnValue) { out.println(indent + returnType.getDeclaration() + - " _returnValue = 0;"); + " _returnValue = 0;"); } else { out.println(indent + returnType.getDeclaration() + " _returnValue;"); } } + // Emit local variable declarations for EGL Handles + // + // Example: + // + // EGLSurface surface_native = (EGLHandle)fromEGLHandle(_env, surfaceClass, surfaceConstructor, surface); + // + 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); + + if (jfunc.getArgType(idx).isBuffer() + || jfunc.getArgType(idx).isArray() + || !jfunc.getArgType(idx).isEGLHandle()) + continue; + + CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); + String decl = type.getDeclaration(); + out.println(indent + + decl + " " + cname + "_native = (" + + decl + ") fromEGLHandle(_env, " + + type.getBaseType().toLowerCase() + + "GetHandleID, " + jfunc.getArgName(idx) + + ");"); + } + } + + // Emit local variable declarations for element/sentinel checks + // + // Example: + // + // bool attrib_list_sentinel_found = false; + // + emitLocalVariablesForSentinel(cfunc, out); + // Emit local variable declarations for pointer arguments // // Example: @@ -878,9 +1010,12 @@ public class JniCodeEmitter { int cIndex = jfunc.getArgCIndex(idx); String cname = cfunc.getArgName(cIndex); + if (!jfunc.getArgType(idx).isBuffer() && !jfunc.getArgType(idx).isArray()) + continue; + CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); String decl = type.getDeclaration(); - if (jfunc.getArgType(idx).isArray()) { + if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { out.println(indent + decl + (decl.endsWith("*") ? "" : " ") + @@ -892,10 +1027,10 @@ public class JniCodeEmitter { out.println(indent + "jint " + remaining + ";"); out.println(indent + - decl + - (decl.endsWith("*") ? "" : " ") + - jfunc.getArgName(idx) + - " = (" + decl + ") 0;"); + decl + + (decl.endsWith("*") ? "" : " ") + + jfunc.getArgName(idx) + + " = (" + decl + ") 0;"); } out.println(); @@ -923,11 +1058,13 @@ public class JniCodeEmitter { CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); String decl = type.getDeclaration(); - out.println(indent + "if (!" + cname + ") {"); - out.println(indent + " jniThrowException(_env, " + - "\"java/lang/IllegalArgumentException\", \"" + cname + " == null\");"); - out.println(indent + " goto exit;"); needsExit = true; + out.println(indent + "if (!" + cname + ") {"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + + "_exceptionMessage = \"" + cname + " == null\";"); + out.println(indent + indent + "goto exit;"); out.println(indent + "}"); out.println(indent + "_native" + cname + " = _env->GetStringUTFChars(" + cname + ", 0);"); @@ -936,7 +1073,7 @@ public class JniCodeEmitter { out.println(); } - // Emit 'GetPrimitiveArrayCritical' for arrays + // Emit 'GetPrimitiveArrayCritical' for non-object arrays // Emit 'GetPointer' calls for Buffer pointers int bufArgIdx = 0; if (nonPrimitiveArgs.size() > 0) { @@ -950,29 +1087,24 @@ public class JniCodeEmitter { 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 + " jniThrowException(_env, " + - "\"java/lang/IllegalArgumentException\", " + - "\"" + cname + " == null\");"); - out.println(indent + " goto exit;"); + if (jfunc.getArgType(idx).isArray() + && !jfunc.getArgType(idx).isEGLHandle()) { needsExit = true; + out.println(indent + "if (!" + cname + "_ref) {"); + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + + "_exceptionMessage = \"" + cname +" == null\";"); + out.println(indent + indent + "goto exit;"); out.println(indent + "}"); - out.println(indent + "if (" + offset + " < 0) {"); - if (emitExceptionCheck) { - out.println(indent + indent + "_exception = 1;"); - } - out.println(indent + " jniThrowException(_env, " + - "\"java/lang/IllegalArgumentException\", \"" + offset + " < 0\");"); - out.println(indent + " goto exit;"); - needsExit = true; + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + + "_exceptionMessage = \"" + offset +" < 0\";"); + out.println(indent + indent + "goto exit;"); out.println(indent + "}"); out.println(indent + remaining + " = " + @@ -997,10 +1129,44 @@ public class JniCodeEmitter { jfunc.getArgName(idx) + "_ref, (jboolean *)0);"); out.println(indent + - cname + " = " + cname + "_base + " + offset + - ";"); + cname + " = " + cname + "_base + " + offset + ";"); + + emitSentinelCheck(cfunc, cname, out, false, + emitExceptionCheck, offset, + remaining, indent); out.println(); - } else { + } else if (jfunc.getArgType(idx).isArray() + && jfunc.getArgType(idx).isEGLHandle()) { + needsExit = true; + out.println(indent + "if (!" + cname + "_ref) {"); + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + "_exceptionMessage = \"" + cname +" == null\";"); + out.println(indent + indent + "goto exit;"); + out.println(indent + "}"); + out.println(indent + "if (" + offset + " < 0) {"); + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + + "_exceptionType = \"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + "_exceptionMessage = \"" + offset +" < 0\";"); + out.println(indent + indent + "goto exit;"); + 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 + + jfunc.getArgName(idx) + " = new " + + cfunc.getArgType(cIndex).getBaseType() + + "["+ remaining + "];"); + out.println(); + } else if (jfunc.getArgType(idx).isBuffer()) { String array = numBufferArgs <= 1 ? "_array" : "_" + bufferArgNames.get(bufArgIdx++) + "Array"; @@ -1019,7 +1185,7 @@ public class JniCodeEmitter { cname + "_buf);"); String iii = " "; out.println(iii + indent + "if ( ! " + cname + " ) {"); - out.println(iii + iii + indent + "return;"); + out.println(iii + indent + indent + "return;"); out.println(iii + indent + "}"); } else { out.println(indent + @@ -1075,18 +1241,23 @@ public class JniCodeEmitter { for (int i = 0; i < numArgs; i++) { String typecast; if (i == numArgs - 1 && isVBOPointerFunc) { - typecast = "const GLvoid *"; + typecast = "(const GLvoid *)"; } else { - typecast = cfunc.getArgType(i).getDeclaration(); + typecast = "(" + cfunc.getArgType(i).getDeclaration() + ")"; } out.print(indent + indent + - "(" + - typecast + - ")"); + typecast); + if (cfunc.getArgType(i).isConstCharPointer()) { out.print("_native"); } - out.print(cfunc.getArgName(i)); + + if (cfunc.getArgType(i).isEGLHandle() && + !cfunc.getArgType(i).isPointer()){ + out.print(cfunc.getArgName(i)+"_native"); + } else { + out.print(cfunc.getArgName(i)); + } if (i == numArgs - 1) { if (isPointerFunc) { @@ -1114,7 +1285,7 @@ public class JniCodeEmitter { int idx = nonPrimitiveArgs.get(i).intValue(); int cIndex = jfunc.getArgCIndex(idx); - if (jfunc.getArgType(idx).isArray()) { + if (jfunc.getArgType(idx).isArray() && !jfunc.getArgType(idx).isClass()) { // If the argument is 'const', GL will not write to it. // In this case, we can use the 'JNI_ABORT' flag to avoid @@ -1130,8 +1301,7 @@ public class JniCodeEmitter { "_base,"); out.println(indent + indent + indent + (cfunc.getArgType(cIndex).isConst() ? - "JNI_ABORT" : - "_exception ? JNI_ABORT: 0") + + "JNI_ABORT" : "_exception ? JNI_ABORT: 0" ) + ");"); out.println(indent + "}"); } else if (jfunc.getArgType(idx).isBuffer()) { @@ -1144,8 +1314,8 @@ public class JniCodeEmitter { cfunc.getArgName(cIndex) + ", " + (cfunc.getArgType(cIndex).isConst() ? - "JNI_FALSE" : "_exception ? JNI_FALSE :" + - " JNI_TRUE") + + "JNI_FALSE" : (emitExceptionCheck ? + "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + ");"); out.println(indent + "}"); } @@ -1168,9 +1338,60 @@ public class JniCodeEmitter { out.println(); } + // Copy results back to java arrays + if (nonPrimitiveArgs.size() > 0) { + for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + String baseType = cfunc.getArgType(cIndex).getBaseType().toLowerCase(); + if (jfunc.getArgType(idx).isArray() && jfunc.getArgType(idx).isClass()) { + remaining = ((numArrays + numBuffers) <= 1) ? "_remaining" : + "_" + cfunc.getArgName(cIndex) + "Remaining"; + offset = numArrays <= 1 ? "offset" : cfunc.getArgName(cIndex) + "Offset"; + out.println(indent + + "if (" + jfunc.getArgName(idx) + ") {"); + out.println(indent + indent + + "for (int i = 0; i < " + remaining + "; i++) {"); + out.println(indent + indent + indent + + "jobject " + cfunc.getArgName(cIndex) + + "_new = toEGLHandle(_env, " + baseType + + "Class, " + baseType + "Constructor, " + + cfunc.getArgName(cIndex) + "[i]);"); + out.println(indent + indent + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->SetObjectArrayElement(" + + (mUseCPlusPlus ? "" : "_env, ") + + cfunc.getArgName(cIndex) + + "_ref, i + " + offset + ", " + + cfunc.getArgName(cIndex) + "_new);"); + out.println(indent + indent + "}"); + out.println(indent + indent + + "delete[] " + jfunc.getArgName(idx) + ";"); + out.println(indent + "}"); + } + } + } + + + // Throw exception if there is one + if (emitExceptionCheck) { + out.println(indent + "if (_exception) {"); + out.println(indent + indent + + "jniThrowException(_env, _exceptionType, _exceptionMessage);"); + out.println(indent + "}"); + + } + if (!isVoid) { - out.println(indent + "return _returnValue;"); + if (cfunc.getType().isEGLHandle()) { + String baseType = cfunc.getType().getBaseType().toLowerCase(); + out.println(indent + + "return toEGLHandle(_env, " + baseType + "Class, " + + baseType + "Constructor, _returnValue);"); + } else { + out.println(indent + "return _returnValue;"); + } } out.println("}"); -- cgit v1.1