mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-13 14:51:51 -04:00
Changes
- Moved all gl4es+egl management into gl_bridge.c and gl_bridge.h - Also, reimplemented it from scratch with surface swapping support
This commit is contained in:
parent
424e6bb630
commit
1261e4a7ea
@ -143,7 +143,10 @@ public class MinecraftGLSurface extends View {
|
||||
private boolean isCalled = false;
|
||||
@Override
|
||||
public void surfaceCreated(@NonNull SurfaceHolder holder) {
|
||||
if(isCalled) return;
|
||||
if(isCalled) {
|
||||
JREUtils.setupBridgeWindow(surfaceView.getHolder().getSurface());
|
||||
return;
|
||||
}
|
||||
isCalled = true;
|
||||
|
||||
realStart(surfaceView.getHolder().getSurface());
|
||||
@ -168,7 +171,10 @@ public class MinecraftGLSurface extends View {
|
||||
private boolean isCalled = false;
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
|
||||
if(isCalled) return;
|
||||
if(isCalled) {
|
||||
JREUtils.setupBridgeWindow(new Surface(surface));
|
||||
return;
|
||||
}
|
||||
isCalled = true;
|
||||
|
||||
realStart(new Surface(textureView.getSurfaceTexture()));
|
||||
|
@ -33,6 +33,7 @@ LOCAL_MODULE := pojavexec
|
||||
# -DGLES_TEST
|
||||
LOCAL_SRC_FILES := \
|
||||
egl_bridge.c \
|
||||
gl_bridge.c \
|
||||
input_bridge_v3.c \
|
||||
jre_launcher.c \
|
||||
utils.c
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <android/rect.h>
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
#include "gl_bridge.h"
|
||||
// region OSMESA internals
|
||||
|
||||
struct pipe_screen;
|
||||
@ -668,6 +669,9 @@ void pojavTerminate() {
|
||||
|
||||
JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_setupBridgeWindow(JNIEnv* env, jclass clazz, jobject surface) {
|
||||
potatoBridge.androidWindow = ANativeWindow_fromSurface(env, surface);
|
||||
if(config_renderer == RENDERER_GL4ES) {
|
||||
gl_setup_window(potatoBridge.androidWindow);
|
||||
}
|
||||
char *ptrStr;
|
||||
asprintf(&ptrStr, "%ld", (long) potatoBridge.androidWindow);
|
||||
setenv("POJAV_WINDOW_PTR", ptrStr, 1);
|
||||
@ -813,14 +817,20 @@ int pojavInit() {
|
||||
loadSymbolsVirGL();
|
||||
} else if (strncmp("opengles", renderer, 8) == 0) {
|
||||
config_renderer = RENDERER_GL4ES;
|
||||
loadSymbols();
|
||||
//loadSymbols();
|
||||
} else if (strcmp(renderer, "vulkan_zink") == 0) {
|
||||
config_renderer = RENDERER_VK_ZINK;
|
||||
setenv("GALLIUM_DRIVER","zink",1);
|
||||
loadSymbols();
|
||||
}
|
||||
|
||||
if (config_renderer == RENDERER_GL4ES || config_renderer == RENDERER_VIRGL) {
|
||||
if(config_renderer == RENDERER_GL4ES) {
|
||||
if(gl_init()) {
|
||||
gl_setup_window(potatoBridge.androidWindow);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (config_renderer == RENDERER_VIRGL) {
|
||||
if (potatoBridge.eglDisplay == NULL || potatoBridge.eglDisplay == EGL_NO_DISPLAY) {
|
||||
potatoBridge.eglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);
|
||||
if (potatoBridge.eglDisplay == EGL_NO_DISPLAY) {
|
||||
@ -938,12 +948,7 @@ void pojavSwapBuffers() {
|
||||
}
|
||||
switch (config_renderer) {
|
||||
case RENDERER_GL4ES: {
|
||||
if (!eglSwapBuffers_p(potatoBridge.eglDisplay, eglGetCurrentSurface_p(EGL_DRAW))) {
|
||||
if (eglGetError_p() == EGL_BAD_SURFACE) {
|
||||
stopSwapBuffers = true;
|
||||
closeGLFWWindow();
|
||||
}
|
||||
}
|
||||
gl_swap_buffers();
|
||||
} break;
|
||||
|
||||
case RENDERER_VIRGL: {
|
||||
@ -993,46 +998,9 @@ void pojavMakeCurrent(void* window) {
|
||||
// printf("OSMDroid: skipped context reset\n");
|
||||
// return JNI_TRUE;
|
||||
//}
|
||||
|
||||
if (config_renderer == RENDERER_GL4ES) {
|
||||
EGLContext *currCtx = eglGetCurrentContext_p();
|
||||
printf("EGLBridge: Comparing: thr=%d, this=%p, curr=%p\n", gettid(), window, currCtx);
|
||||
if (currCtx == NULL || window == 0) {
|
||||
/*if (window != 0x0 && potatoBridge.eglContextOld != NULL && potatoBridge.eglContextOld != (void *) window) {
|
||||
// Create new pbuffer per thread
|
||||
// TODO get window size for 2nd+ window!
|
||||
int surfaceWidth, surfaceHeight;
|
||||
eglQuerySurface(potatoBridge.eglDisplay, potatoBridge.eglSurface, EGL_WIDTH, &surfaceWidth);
|
||||
eglQuerySurface(potatoBridge.eglDisplay, potatoBridge.eglSurface, EGL_HEIGHT, &surfaceHeight);
|
||||
int surfaceAttr[] = {
|
||||
EGL_WIDTH, surfaceWidth,
|
||||
EGL_HEIGHT, surfaceHeight,
|
||||
EGL_NONE
|
||||
};
|
||||
potatoBridge.eglSurface = eglCreatePbufferSurface(potatoBridge.eglDisplay, config, surfaceAttr);
|
||||
printf("EGLBridge: created pbuffer surface %p for context %p\n", potatoBridge.eglSurface, window);
|
||||
}*/
|
||||
//potatoBridge.eglContextOld = (void *) window;
|
||||
// eglMakeCurrent(potatoBridge.eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
printf("EGLBridge: Making current on window %p on thread %d\n", window, gettid());
|
||||
egl_make_current((void *)window);
|
||||
|
||||
// Test
|
||||
#ifdef GLES_TEST
|
||||
glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
eglSwapBuffers(potatoBridge.eglDisplay, potatoBridge.eglSurface);
|
||||
printf("First frame error: %p\n", eglGetError());
|
||||
#endif
|
||||
|
||||
// idk this should convert or just `return success;`...
|
||||
return; //success == EGL_TRUE ? JNI_TRUE : JNI_FALSE;
|
||||
} else {
|
||||
// (*env)->ThrowNew(env,(*env)->FindClass(env,"java/lang/Exception"),"Trace exception");
|
||||
return;
|
||||
}
|
||||
if(config_renderer == RENDERER_GL4ES) {
|
||||
gl_make_current((render_bundle_t*)window);
|
||||
}
|
||||
|
||||
if (config_renderer == RENDERER_VK_ZINK || config_renderer == RENDERER_VIRGL) {
|
||||
printf("OSMDroid: making current\n");
|
||||
OSMesaMakeCurrent_p((OSMesaContext)window,gbuffer,GL_UNSIGNED_BYTE,savedWidth,savedHeight);
|
||||
@ -1078,7 +1046,7 @@ Java_org_lwjgl_glfw_GLFW_nativeEglDetachOnCurrentThread(JNIEnv *env, jclass claz
|
||||
|
||||
void* pojavCreateContext(void* contextSrc) {
|
||||
if (config_renderer == RENDERER_GL4ES) {
|
||||
const EGLint ctx_attribs[] = {
|
||||
/*const EGLint ctx_attribs[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, atoi(getenv("LIBGL_ES")),
|
||||
EGL_NONE
|
||||
};
|
||||
@ -1086,7 +1054,8 @@ void* pojavCreateContext(void* contextSrc) {
|
||||
potatoBridge.eglContext = ctx;
|
||||
printf("EGLBridge: Created CTX pointer = %p\n",ctx);
|
||||
//(*env)->ThrowNew(env,(*env)->FindClass(env,"java/lang/Exception"),"Trace exception");
|
||||
return (long)ctx;
|
||||
return (long)ctx;*/
|
||||
return gl_init_context(contextSrc);
|
||||
}
|
||||
|
||||
if (config_renderer == RENDERER_VK_ZINK || config_renderer == RENDERER_VIRGL) {
|
||||
@ -1119,7 +1088,9 @@ Java_org_lwjgl_opengl_GL_getNativeWidthHeight(JNIEnv *env, jobject thiz) {
|
||||
}
|
||||
void pojavSwapInterval(int interval) {
|
||||
switch (config_renderer) {
|
||||
case RENDERER_GL4ES:
|
||||
case RENDERER_GL4ES: {
|
||||
gl_swap_interval(interval);
|
||||
} break;
|
||||
case RENDERER_VIRGL: {
|
||||
eglSwapInterval_p(potatoBridge.eglDisplay, interval);
|
||||
} break;
|
||||
|
189
app_pojavlauncher/src/main/jni/gl_bridge.c
Normal file
189
app_pojavlauncher/src/main/jni/gl_bridge.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include <EGL/egl.h>
|
||||
#include <android/log.h>
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
#include "gl_bridge.h"
|
||||
|
||||
//
|
||||
// Created by maks on 17.09.2022.
|
||||
//
|
||||
|
||||
#define STATE_RENDERER_ALIVE 0
|
||||
#define STATE_RENDERER_NEW_WINDOW 1
|
||||
static char* g_LogTag = "GLBridge";
|
||||
|
||||
EGLBoolean (*eglMakeCurrent_p) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
||||
EGLBoolean (*eglDestroyContext_p) (EGLDisplay dpy, EGLContext ctx);
|
||||
EGLBoolean (*eglDestroySurface_p) (EGLDisplay dpy, EGLSurface surface);
|
||||
EGLBoolean (*eglTerminate_p) (EGLDisplay dpy);
|
||||
EGLBoolean (*eglReleaseThread_p) (void);
|
||||
EGLContext (*eglGetCurrentContext_p) (void);
|
||||
EGLDisplay (*eglGetDisplay_p) (NativeDisplayType display);
|
||||
EGLBoolean (*eglInitialize_p) (EGLDisplay dpy, EGLint *major, EGLint *minor);
|
||||
EGLBoolean (*eglChooseConfig_p) (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
|
||||
EGLBoolean (*eglGetConfigAttrib_p) (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
|
||||
EGLBoolean (*eglBindAPI_p) (EGLenum api);
|
||||
EGLSurface (*eglCreatePbufferSurface_p) (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
|
||||
EGLSurface (*eglCreateWindowSurface_p) (EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list);
|
||||
EGLBoolean (*eglSwapBuffers_p) (EGLDisplay dpy, EGLSurface draw);
|
||||
EGLint (*eglGetError_p) (void);
|
||||
EGLContext (*eglCreateContext_p) (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list);
|
||||
EGLBoolean (*eglSwapInterval_p) (EGLDisplay dpy, EGLint interval);
|
||||
EGLSurface (*eglGetCurrentSurface_p) (EGLint readdraw);
|
||||
|
||||
struct ANativeWindow* newWindow;
|
||||
static __thread render_bundle_t* currentBundle;
|
||||
static render_bundle_t* mainWindowBundle;
|
||||
EGLDisplay g_EglDisplay;
|
||||
|
||||
void gl_dlsym_EGL() {
|
||||
void* dl_handle = NULL;
|
||||
if(getenv("POJAVEXEC_EGL")) dl_handle = dlopen(getenv("POJAVEXEC_EGL"), RTLD_LAZY);
|
||||
if(dl_handle == NULL) dl_handle = dlopen("libEGL.so", RTLD_LAZY);
|
||||
if(dl_handle == NULL) abort();
|
||||
eglBindAPI_p = dlsym(dl_handle,"eglBindAPI");
|
||||
eglChooseConfig_p = dlsym(dl_handle, "eglChooseConfig");
|
||||
eglCreateContext_p = dlsym(dl_handle, "eglCreateContext");
|
||||
eglCreatePbufferSurface_p = dlsym(dl_handle, "eglCreatePbufferSurface");
|
||||
eglCreateWindowSurface_p = dlsym(dl_handle, "eglCreateWindowSurface");
|
||||
eglDestroyContext_p = dlsym(dl_handle, "eglDestroyContext");
|
||||
eglDestroySurface_p = dlsym(dl_handle, "eglDestroySurface");
|
||||
eglGetConfigAttrib_p = dlsym(dl_handle, "eglGetConfigAttrib");
|
||||
eglGetCurrentContext_p = dlsym(dl_handle, "eglGetCurrentContext");
|
||||
eglGetDisplay_p = dlsym(dl_handle, "eglGetDisplay");
|
||||
eglGetError_p = dlsym(dl_handle, "eglGetError");
|
||||
eglInitialize_p = dlsym(dl_handle, "eglInitialize");
|
||||
eglMakeCurrent_p = dlsym(dl_handle, "eglMakeCurrent");
|
||||
eglSwapBuffers_p = dlsym(dl_handle, "eglSwapBuffers");
|
||||
eglReleaseThread_p = dlsym(dl_handle, "eglReleaseThread");
|
||||
eglSwapInterval_p = dlsym(dl_handle, "eglSwapInterval");
|
||||
eglTerminate_p = dlsym(dl_handle, "eglTerminate");
|
||||
eglGetCurrentSurface_p = dlsym(dl_handle,"eglGetCurrentSurface");
|
||||
}
|
||||
|
||||
bool gl_init() {
|
||||
gl_dlsym_EGL();
|
||||
g_EglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);
|
||||
if (g_EglDisplay == EGL_NO_DISPLAY) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s",
|
||||
"eglGetDisplay_p(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY");
|
||||
return false;
|
||||
}
|
||||
if (eglInitialize_p(g_EglDisplay, 0, 0) != EGL_TRUE) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglInitialize_p() failed: %04x",
|
||||
eglGetError_p());
|
||||
return false;
|
||||
}
|
||||
eglSwapInterval_p(g_EglDisplay, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
render_bundle_t* gl_init_context(render_bundle_t *share) {
|
||||
render_bundle_t* bundle = malloc(sizeof(render_bundle_t));
|
||||
const EGLint egl_attributes[] = { EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE };
|
||||
EGLint num_configs = 0;
|
||||
if (eglChooseConfig_p(g_EglDisplay, egl_attributes, NULL, 0, &num_configs) != EGL_TRUE) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglChooseConfig_p() failed: %04x",
|
||||
eglGetError_p());
|
||||
free(bundle);
|
||||
return NULL;
|
||||
}
|
||||
if (num_configs == 0) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s",
|
||||
"eglChooseConfig_p() found no matching config");
|
||||
free(bundle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the first matching config
|
||||
eglChooseConfig_p(g_EglDisplay, egl_attributes, &bundle->config, 1, &num_configs);
|
||||
eglGetConfigAttrib_p(g_EglDisplay, bundle->config, EGL_NATIVE_VISUAL_ID, &bundle->format);
|
||||
|
||||
int libgl_es = strtol(getenv("LIBGL_ES"), NULL, 0);
|
||||
if(libgl_es < 0 || libgl_es > INT16_MAX) libgl_es = 2;
|
||||
const EGLint egl_context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, libgl_es, EGL_NONE };
|
||||
bundle->context = eglCreateContext_p(g_EglDisplay, bundle->context, share == NULL ? EGL_NO_CONTEXT : share->context, egl_context_attributes);
|
||||
|
||||
if (bundle->context == EGL_NO_CONTEXT) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglCreateContext_p() finished with error: %04x",
|
||||
eglGetError_p());
|
||||
free(bundle);
|
||||
return NULL;
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
void gl_set_android_surface(render_bundle_t* bundle) {
|
||||
if(bundle->nativeSurface != NULL) {
|
||||
ANativeWindow_release(bundle->nativeSurface);
|
||||
}
|
||||
if(bundle->newNativeSurface != NULL) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "Switching to new native surface");
|
||||
bundle->nativeSurface = bundle->newNativeSurface;
|
||||
ANativeWindow_acquire(bundle->nativeSurface);
|
||||
ANativeWindow_setBuffersGeometry(bundle->nativeSurface, 0, 0, bundle->format);
|
||||
bundle->surface = eglCreateWindowSurface_p(g_EglDisplay, bundle->config, bundle->nativeSurface, NULL);
|
||||
}else{
|
||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "No new native surface, disabling surfaces");
|
||||
bundle->nativeSurface = NULL;
|
||||
bundle->surface = NULL;
|
||||
}
|
||||
//eglMakeCurrent_p(g_EglDisplay, bundle->surface, bundle->surface, bundle->context);
|
||||
}
|
||||
|
||||
void gl_make_current(render_bundle_t* bundle) {
|
||||
if(bundle == NULL) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, g_LogTag, "Cannot make a NULL bundle current!");
|
||||
abort();
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Making current, surface=%p, nativeSurface=%p, newNativeSurface=%p", bundle->surface, bundle->nativeSurface, bundle->newNativeSurface);
|
||||
if(bundle->surface == NULL) { //it likely will be on the first run
|
||||
if(bundle->nativeSurface || bundle->newNativeSurface) gl_set_android_surface(bundle);
|
||||
}
|
||||
if(eglMakeCurrent_p(g_EglDisplay, bundle->surface, bundle->surface, bundle->context)) {
|
||||
currentBundle = bundle;
|
||||
}else __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglMakeCurrent returned with error: %04x", eglGetError_p());
|
||||
|
||||
}
|
||||
|
||||
void gl_swap_buffers() {
|
||||
if(mainWindowBundle == NULL) {
|
||||
mainWindowBundle = currentBundle;
|
||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is now %p", mainWindowBundle);
|
||||
mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
|
||||
mainWindowBundle->newNativeSurface = newWindow;
|
||||
}
|
||||
if(currentBundle->state == STATE_RENDERER_NEW_WINDOW) {
|
||||
eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); //detach everything to destroy the old EGLSurface
|
||||
if(currentBundle->surface != NULL) eglDestroySurface_p(g_EglDisplay, currentBundle->surface);
|
||||
gl_set_android_surface(currentBundle);
|
||||
eglMakeCurrent_p(g_EglDisplay, currentBundle->surface, currentBundle->surface, currentBundle->context);
|
||||
currentBundle->state = STATE_RENDERER_ALIVE;
|
||||
}
|
||||
if(currentBundle->surface != NULL)
|
||||
if(!eglSwapBuffers_p(g_EglDisplay, currentBundle->surface) && eglGetError_p() == EGL_BAD_SURFACE) {
|
||||
eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglDestroySurface_p(g_EglDisplay, currentBundle->surface);
|
||||
currentBundle->surface = NULL;
|
||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "The window has died, awaiting window change");
|
||||
eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, currentBundle->context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gl_setup_window(struct ANativeWindow* window) {
|
||||
if(mainWindowBundle != NULL) {
|
||||
mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
|
||||
mainWindowBundle->newNativeSurface = window;
|
||||
}else{
|
||||
newWindow = window;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_swap_interval(int swapInterval) {
|
||||
eglSwapInterval_p(g_EglDisplay, swapInterval);
|
||||
}
|
26
app_pojavlauncher/src/main/jni/gl_bridge.h
Normal file
26
app_pojavlauncher/src/main/jni/gl_bridge.h
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by maks on 17.09.2022.
|
||||
//
|
||||
|
||||
#ifndef POJAVLAUNCHER_GL_BRIDGE_H
|
||||
#define POJAVLAUNCHER_GL_BRIDGE_H
|
||||
|
||||
typedef struct {
|
||||
char state;
|
||||
EGLConfig config;
|
||||
EGLint format;
|
||||
EGLContext context;
|
||||
EGLSurface surface;
|
||||
struct ANativeWindow *nativeSurface;
|
||||
struct ANativeWindow *newNativeSurface;
|
||||
} render_bundle_t;
|
||||
|
||||
bool gl_init();
|
||||
render_bundle_t* gl_init_context(render_bundle_t* share);
|
||||
void gl_make_current(render_bundle_t* bundle);
|
||||
void gl_swap_buffers();
|
||||
void gl_setup_window(struct ANativeWindow* window);
|
||||
void gl_swap_interval(int swapInterval);
|
||||
|
||||
|
||||
#endif //POJAVLAUNCHER_GL_BRIDGE_H
|
Loading…
x
Reference in New Issue
Block a user