Path: blob/v3_openjdk/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c
2128 views
#include <EGL/egl.h>1#include <android/native_window.h>2#include <android/native_window_jni.h>3#include <string.h>4#include <malloc.h>5#include <stdlib.h>6#include <dlfcn.h>7#include <stdbool.h>8#include <environ/environ.h>9#include "gl_bridge.h"10#include "egl_loader.h"1112#define TAG __FILE_NAME__13#include <log.h>1415//16// Created by maks on 17.09.2022.17//1819static __thread gl_render_window_t* currentBundle;20static EGLDisplay g_EglDisplay;2122bool gl_init() {23if(!dlsym_EGL()) return false;24g_EglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);25if (g_EglDisplay == EGL_NO_DISPLAY) {26LOGE("%s", "eglGetDisplay_p(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY");27return false;28}29if (eglInitialize_p(g_EglDisplay, 0, 0) != EGL_TRUE) {30LOGE("eglInitialize_p() failed: %04x", eglGetError_p());31return false;32}33return true;34}3536gl_render_window_t* gl_get_current() {37return currentBundle;38}3940static void gl4esi_get_display_dimensions(int* width, int* height) {41if(currentBundle == NULL) goto zero;42EGLSurface surface = currentBundle->surface;43// Fetch dimensions from the EGL surface - the most reliable way44EGLBoolean result_width = eglQuerySurface_p(g_EglDisplay, surface, EGL_WIDTH, width);45EGLBoolean result_height = eglQuerySurface_p(g_EglDisplay, surface, EGL_HEIGHT, height);46if(!result_width || !result_height) goto zero;47return;4849zero:50// No idea what to do, but feeding gl4es incorrect or non-initialized dimensions may be51// a bad idea. Set to zero in case of errors.52*width = 0;53*height = 0;54}5556gl_render_window_t* gl_init_context(gl_render_window_t *share) {57gl_render_window_t* bundle = malloc(sizeof(gl_render_window_t));58memset(bundle, 0, sizeof(gl_render_window_t));59EGLint 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_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE };60EGLint num_configs = 0;6162if (eglChooseConfig_p(g_EglDisplay, egl_attributes, NULL, 0, &num_configs) != EGL_TRUE) {63LOGE("eglChooseConfig_p() failed: %04x", eglGetError_p());64free(bundle);65return NULL;66}67if (num_configs == 0) {68LOGE("%s", "eglChooseConfig_p() found no matching config");69free(bundle);70return NULL;71}7273// Get the first matching config74eglChooseConfig_p(g_EglDisplay, egl_attributes, &bundle->config, 1, &num_configs);75eglGetConfigAttrib_p(g_EglDisplay, bundle->config, EGL_NATIVE_VISUAL_ID, &bundle->format);7677{78EGLBoolean bindResult;79if (strncmp(getenv("POJAV_RENDERER"), "opengles3_desktopgl", 19) == 0) {80printf("EGLBridge: Binding to desktop OpenGL\n");81bindResult = eglBindAPI_p(EGL_OPENGL_API);82} else {83printf("EGLBridge: Binding to OpenGL ES\n");84bindResult = eglBindAPI_p(EGL_OPENGL_ES_API);85}86if (!bindResult) printf("EGLBridge: bind failed: %p\n", eglGetError_p());87}8889int libgl_es = strtol(getenv("LIBGL_ES"), NULL, 0);90if(libgl_es < 0 || libgl_es > INT16_MAX) libgl_es = 2;91const EGLint egl_context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, libgl_es, EGL_NONE };92bundle->context = eglCreateContext_p(g_EglDisplay, bundle->config, share == NULL ? EGL_NO_CONTEXT : share->context, egl_context_attributes);9394if (bundle->context == EGL_NO_CONTEXT) {95LOGE("eglCreateContext_p() finished with error: %04x", eglGetError_p());96free(bundle);97return NULL;98}99return bundle;100}101102void gl_swap_surface(gl_render_window_t* bundle) {103if(bundle->nativeSurface != NULL) {104ANativeWindow_release(bundle->nativeSurface);105}106if(bundle->surface != NULL) eglDestroySurface_p(g_EglDisplay, bundle->surface);107if(bundle->newNativeSurface != NULL) {108LOGI("Switching to new native surface");109bundle->nativeSurface = bundle->newNativeSurface;110bundle->newNativeSurface = NULL;111ANativeWindow_acquire(bundle->nativeSurface);112ANativeWindow_setBuffersGeometry(bundle->nativeSurface, 0, 0, bundle->format);113bundle->surface = eglCreateWindowSurface_p(g_EglDisplay, bundle->config, bundle->nativeSurface, NULL);114}else{115LOGI("No new native surface, switching to 1x1 pbuffer");116bundle->nativeSurface = NULL;117const EGLint pbuffer_attrs[] = {EGL_WIDTH, 1 , EGL_HEIGHT, 1, EGL_NONE};118bundle->surface = eglCreatePbufferSurface_p(g_EglDisplay, bundle->config, pbuffer_attrs);119}120//eglMakeCurrent_p(g_EglDisplay, bundle->surface, bundle->surface, bundle->context);121}122123void gl_make_current(gl_render_window_t* bundle) {124125if(bundle == NULL) {126if(eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {127currentBundle = NULL;128}129return;130}131bool hasSetMainWindow = false;132if(pojav_environ->mainWindowBundle == NULL) {133pojav_environ->mainWindowBundle = (basic_render_window_t*)bundle;134LOGI("Main window bundle is now %p", pojav_environ->mainWindowBundle);135pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;136hasSetMainWindow = true;137}138LOGI("Making current, surface=%p, nativeSurface=%p, newNativeSurface=%p", bundle->surface, bundle->nativeSurface, bundle->newNativeSurface);139if(bundle->surface == NULL) { //it likely will be on the first run140gl_swap_surface(bundle);141}142if(eglMakeCurrent_p(g_EglDisplay, bundle->surface, bundle->surface, bundle->context)) {143currentBundle = bundle;144}else {145if(hasSetMainWindow) {146pojav_environ->mainWindowBundle->newNativeSurface = NULL;147gl_swap_surface((gl_render_window_t*)pojav_environ->mainWindowBundle);148pojav_environ->mainWindowBundle = NULL;149}150LOGE("eglMakeCurrent returned with error: %04x", eglGetError_p());151}152153}154155void gl_swap_buffers() {156if(currentBundle->state == STATE_RENDERER_NEW_WINDOW) {157eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); //detach everything to destroy the old EGLSurface158gl_swap_surface(currentBundle);159eglMakeCurrent_p(g_EglDisplay, currentBundle->surface, currentBundle->surface, currentBundle->context);160currentBundle->state = STATE_RENDERER_ALIVE;161}162if(currentBundle->surface != NULL)163if(!eglSwapBuffers_p(g_EglDisplay, currentBundle->surface) && eglGetError_p() == EGL_BAD_SURFACE) {164eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);165currentBundle->newNativeSurface = NULL;166gl_swap_surface(currentBundle);167eglMakeCurrent_p(g_EglDisplay, currentBundle->surface, currentBundle->surface, currentBundle->context);168LOGI("The window has died, awaiting window change");169}170171}172173void gl_setup_window() {174if(pojav_environ->mainWindowBundle != NULL) {175LOGI("Main window bundle is not NULL, changing state");176pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;177pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;178}179}180181void gl_swap_interval(int swapInterval) {182if(pojav_environ->force_vsync) swapInterval = 1;183184eglSwapInterval_p(g_EglDisplay, swapInterval);185}186187JNIEXPORT void JNICALL188Java_org_lwjgl_opengl_PojavRendererInit_nativeInitGl4esInternals(JNIEnv *env, jclass clazz,189jobject function_provider) {190LOGI("GL4ES internals initializing...");191jclass funcProviderClass = (*env)->GetObjectClass(env, function_provider);192jmethodID method_getFunctionAddress = (*env)->GetMethodID(env, funcProviderClass, "getFunctionAddress", "(Ljava/lang/CharSequence;)J");193#define GETSYM(N) ((*env)->CallLongMethod(env, function_provider, method_getFunctionAddress, (*env)->NewStringUTF(env, N)));194195void (*set_getmainfbsize)(void (*new_getMainFBSize)(int* width, int* height)) = (void*)GETSYM("set_getmainfbsize");196if(set_getmainfbsize != NULL) {197LOGI("GL4ES internals initialized dimension callback");198set_getmainfbsize(gl4esi_get_display_dimensions);199}200201#undef GETSYM202}203204205