diff --git a/app_pojavlauncher/src/main/java/dalvik/annotation/optimization/CriticalNative.java b/app_pojavlauncher/src/main/java/dalvik/annotation/optimization/CriticalNative.java new file mode 100644 index 000000000..731977c1a --- /dev/null +++ b/app_pojavlauncher/src/main/java/dalvik/annotation/optimization/CriticalNative.java @@ -0,0 +1,12 @@ +package dalvik.annotation.optimization; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +// Dummy CriticalNative annotation. On devices which dont have it this declaration will prevent errors. +// On devices that do have it it will be overridden by the system one and work as usual +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.METHOD) +public @interface CriticalNative { +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CriticalNativeTest.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CriticalNativeTest.java new file mode 100644 index 000000000..434b0e44b --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CriticalNativeTest.java @@ -0,0 +1,11 @@ +package net.kdt.pojavlaunch; + +import dalvik.annotation.optimization.CriticalNative; + +public class CriticalNativeTest { + @CriticalNative + public static native void testCriticalNative(int arg0, int arg1); + public static void invokeTest() { + testCriticalNative(0, 0); + } +} diff --git a/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java b/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java index da635dce0..c60709a57 100644 --- a/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java +++ b/app_pojavlauncher/src/main/java/org/lwjgl/glfw/CallbackBridge.java @@ -5,6 +5,8 @@ import android.content.*; import android.view.Choreographer; import java.util.ArrayList; +import dalvik.annotation.optimization.CriticalNative; + public class CallbackBridge { public static Choreographer sChoreographer = Choreographer.getInstance(); private static boolean isGrabbing = false; @@ -211,17 +213,17 @@ public class CallbackBridge { } } - public static native void nativeSetUseInputStackQueue(boolean useInputStackQueue); + @CriticalNative public static native void nativeSetUseInputStackQueue(boolean useInputStackQueue); - private static native boolean nativeSendChar(char codepoint); + @CriticalNative private static native boolean nativeSendChar(char codepoint); // GLFW: GLFWCharModsCallback deprecated, but is Minecraft still use? - private static native boolean nativeSendCharMods(char codepoint, int mods); - private static native void nativeSendKey(int key, int scancode, int action, int mods); + @CriticalNative private static native boolean nativeSendCharMods(char codepoint, int mods); + @CriticalNative private static native void nativeSendKey(int key, int scancode, int action, int mods); // private static native void nativeSendCursorEnter(int entered); - private static native void nativeSendCursorPos(float x, float y); - private static native void nativeSendMouseButton(int button, int action, int mods); - private static native void nativeSendScroll(double xoffset, double yoffset); - private static native void nativeSendScreenSize(int width, int height); + @CriticalNative private static native void nativeSendCursorPos(float x, float y); + @CriticalNative private static native void nativeSendMouseButton(int button, int action, int mods); + @CriticalNative private static native void nativeSendScroll(double xoffset, double yoffset); + @CriticalNative private static native void nativeSendScreenSize(int width, int height); public static native void nativeSetWindowAttrib(int attrib, int value); static { System.loadLibrary("pojavexec"); diff --git a/app_pojavlauncher/src/main/jni/input_bridge_v3.c b/app_pojavlauncher/src/main/jni/input_bridge_v3.c index 56f82c117..c58fcf4f7 100644 --- a/app_pojavlauncher/src/main/jni/input_bridge_v3.c +++ b/app_pojavlauncher/src/main/jni/input_bridge_v3.c @@ -33,6 +33,7 @@ jint (*orig_ProcessImpl_forkAndExec)(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream); +static void registerFunctions(JNIEnv *env); jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) { if (pojav_environ->dalvikJavaVMPtr == NULL) { @@ -59,7 +60,13 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) { pojav_environ->mouseDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetDirectBufferAddress(pojav_environ->runtimeJNIEnvPtr_JRE, mouseDownBufferJ); hookExec(); } - + + if(pojav_environ->dalvikJavaVMPtr == vm) { + //perform in all DVM instances, not only during first ever set up + JNIEnv *env; + (*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4); + registerFunctions(env); + } pojav_environ->isGrabbing = JNI_FALSE; return JNI_VERSION_1_4; @@ -200,12 +207,15 @@ void hookExec() { printf("Registered forkAndExec\n"); } -JNIEXPORT void JNICALL -Java_org_lwjgl_glfw_CallbackBridge_nativeSetUseInputStackQueue(__attribute__((unused)) JNIEnv *env, __attribute__((unused)) jclass clazz, - jboolean use_input_stack_queue) { + +void critical_set_stackqueue(jboolean use_input_stack_queue) { pojav_environ->isUseStackQueueCall = (int) use_input_stack_queue; } +void noncritical_set_stackqueue(__attribute__((unused)) JNIEnv *env, __attribute__((unused)) jclass clazz, jboolean use_input_stack_queue) { + critical_set_stackqueue(use_input_stack_queue); +} + JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, __attribute__((unused)) jclass clazz, jint action, jbyteArray copySrc) { #ifdef DEBUG LOGD("Debug: Clipboard access is going on\n", pojav_environ->isUseStackQueueCall); @@ -252,7 +262,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(__at pojav_environ->isGrabbing = grabbing; } -JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jchar codepoint /* jint codepoint */) { +jboolean critical_send_char(jchar codepoint) { if (pojav_environ->GLFW_invoke_Char && pojav_environ->isInputReady) { if (pojav_environ->isUseStackQueueCall) { sendData(EVENT_TYPE_CHAR, codepoint, 0, 0, 0); @@ -264,7 +274,11 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendChar(__a return JNI_FALSE; } -JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jchar codepoint, jint mods) { +jboolean noncritical_send_char(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jchar codepoint) { + return critical_send_char(codepoint); +} + +jboolean critical_send_char_mods(jchar codepoint, jint mods) { if (pojav_environ->GLFW_invoke_CharMods && pojav_environ->isInputReady) { if (pojav_environ->isUseStackQueueCall) { sendData(EVENT_TYPE_CHAR_MODS, (int) codepoint, mods, 0, 0); @@ -275,6 +289,10 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods } return JNI_FALSE; } + +jboolean noncritical_send_char_mods(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jchar codepoint, jint mods) { + return critical_send_char_mods(codepoint, mods); +} /* JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorEnter(JNIEnv* env, jclass clazz, jint entered) { if (pojav_environ->GLFW_invoke_CursorEnter && pojav_environ->isInputReady) { @@ -282,7 +300,8 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorEnter( } } */ -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jfloat x, jfloat y) { + +void critical_send_cursor_pos(jfloat x, jfloat y) { #ifdef DEBUG LOGD("Sending cursor position \n"); #endif @@ -313,11 +332,15 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(__ } } } + +void noncritical_send_cursor_pos(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jfloat x, jfloat y) { + critical_send_cursor_pos(x, y); +} #define max(a,b) \ ({ __typeof__ (a) _a = (a); \ __typeof__ (b) _b = (b); \ _a > _b ? _a : _b; }) -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jint key, jint scancode, jint action, jint mods) { +void critical_send_key(jint key, jint scancode, jint action, jint mods) { if (pojav_environ->GLFW_invoke_Key && pojav_environ->isInputReady) { pojav_environ->keyDownBuffer[max(0, key-31)] = (jbyte) action; if (pojav_environ->isUseStackQueueCall) { @@ -327,10 +350,11 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(__attrib } } } +void noncritical_send_key(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jint key, jint scancode, jint action, jint mods) { + critical_send_key(key, scancode, action, mods); +} - - -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jint button, jint action, jint mods) { +void critical_send_mouse_button(jint button, jint action, jint mods) { if (pojav_environ->GLFW_invoke_MouseButton && pojav_environ->isInputReady) { pojav_environ->mouseDownBuffer[max(0, button)] = (jbyte) action; if (pojav_environ->isUseStackQueueCall) { @@ -341,7 +365,11 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton( } } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jint width, jint height) { +void noncritical_send_mouse_button(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jint button, jint action, jint mods) { + critical_send_mouse_button(button, action, mods); +} + +void critical_send_screen_size(jint width, jint height) { pojav_environ->savedWidth = width; pojav_environ->savedHeight = height; if (pojav_environ->isInputReady) { @@ -352,7 +380,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(_ pojav_environ->GLFW_invoke_FramebufferSize((void*) pojav_environ->showingWindow, width, height); } } - + if (pojav_environ->GLFW_invoke_WindowSize) { if (pojav_environ->isUseStackQueueCall) { sendData(EVENT_TYPE_WINDOW_SIZE, width, height, 0, 0); @@ -361,11 +389,13 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScreenSize(_ } } } - - // return (pojav_environ->isInputReady && (pojav_environ->GLFW_invoke_FramebufferSize || pojav_environ->GLFW_invoke_WindowSize)); } -JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jdouble xoffset, jdouble yoffset) { +void noncritical_send_screen_size(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jint width, jint height) { + critical_send_screen_size(width, height); +} + +void critical_send_scroll(jdouble xoffset, jdouble yoffset) { if (pojav_environ->GLFW_invoke_Scroll && pojav_environ->isInputReady) { if (pojav_environ->isUseStackQueueCall) { sendData(EVENT_TYPE_SCROLL, (int)xoffset, (int)yoffset, 0, 0); @@ -375,6 +405,11 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(__att } } +void noncritical_send_scroll(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jdouble xoffset, jdouble yoffset) { + critical_send_scroll(xoffset, yoffset); +} + + JNIEXPORT void JNICALL Java_org_lwjgl_glfw_GLFW_nglfwSetShowingWindow(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jlong window) { pojav_environ->showingWindow = (long) window; } @@ -392,3 +427,67 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetWindowAttrib( (jlong) pojav_environ->showingWindow, attrib, value ); } +const static JNINativeMethod critical_fcns[] = { + {"nativeSetUseInputStackQueue", "(Z)V", critical_set_stackqueue}, + {"nativeSendChar", "(C)Z", critical_send_char}, + {"nativeSendCharMods", "(CI)Z", critical_send_char_mods}, + {"nativeSendKey", "(IIII)V", critical_send_key}, + {"nativeSendCursorPos", "(FF)V", critical_send_cursor_pos}, + {"nativeSendMouseButton", "(III)V", critical_send_mouse_button}, + {"nativeSendScroll", "(DD)V", critical_send_scroll}, + {"nativeSendScreenSize", "(II)V", critical_send_screen_size} +}; + +const static JNINativeMethod noncritical_fcns[] = { + {"nativeSetUseInputStackQueue", "(Z)V", noncritical_set_stackqueue}, + {"nativeSendChar", "(C)Z", noncritical_send_char}, + {"nativeSendCharMods", "(CI)Z", noncritical_send_char_mods}, + {"nativeSendKey", "(IIII)V", noncritical_send_key}, + {"nativeSendCursorPos", "(FF)V", noncritical_send_cursor_pos}, + {"nativeSendMouseButton", "(III)V", noncritical_send_mouse_button}, + {"nativeSendScroll", "(DD)V", noncritical_send_scroll}, + {"nativeSendScreenSize", "(II)V", noncritical_send_screen_size} +}; + + +static bool criticalNativeAvailable; + +void dvm_testCriticalNative(void* arg0, void* arg1, void* arg2, void* arg3) { + if(arg0 != 0 && arg2 == 0 && arg3 == 0) { + criticalNativeAvailable = false; + }else if (arg0 == 0 && arg1 == 0){ + criticalNativeAvailable = true; + }else { + criticalNativeAvailable = false; // just to be safe + } +} + +static bool tryCriticalNative(JNIEnv *env) { + static const JNINativeMethod testJNIMethod[] = { + { "testCriticalNative", "(II)V", dvm_testCriticalNative} + }; + jclass criticalNativeTest = (*env)->FindClass(env, "net/kdt/pojavlaunch/CriticalNativeTest"); + if(criticalNativeTest == NULL) { + (*env)->ExceptionClear(env); + return false; + } + jmethodID criticalNativeTestMethod = (*env)->GetStaticMethodID(env, criticalNativeTest, "invokeTest", "()V"); + (*env)->RegisterNatives(env, criticalNativeTest, testJNIMethod, 1); + (*env)->CallStaticVoidMethod(env, criticalNativeTest, criticalNativeTestMethod); + (*env)->UnregisterNatives(env, criticalNativeTest); + return criticalNativeAvailable; +} + +static void registerFunctions(JNIEnv *env) { + bool use_critical_cc = tryCriticalNative(env); + jclass bridge_class = (*env)->FindClass(env, "org/lwjgl/glfw/CallbackBridge"); + if(use_critical_cc) { + __android_log_print(ANDROID_LOG_INFO, "pojavexec", "CriticalNative is available. Enjoy the 4.6x times faster input!"); + }else{ + __android_log_print(ANDROID_LOG_INFO, "pojavexec", "CriticalNative is not available. Upgrade, maybe?"); + } + (*env)->RegisterNatives(env, + bridge_class, + use_critical_cc ? critical_fcns : noncritical_fcns, + sizeof(critical_fcns)/sizeof(critical_fcns[0])); +}