Make use of @CriticalNative annotation for the input system

This commit is contained in:
artdeell 2023-04-25 13:07:57 +03:00
parent 57521c1960
commit 29d89f52a8
4 changed files with 148 additions and 24 deletions

View file

@ -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 {
}

View file

@ -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);
}
}

View file

@ -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");

View file

@ -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]));
}