Refactor: Unified egl_bridge implementation (#4816)

* Start working on bridge unification

* Fin[bridge]: unified bridge structure

* Fix[egl_bridge]: remove legacy functions and make initialization more early

* Fix[bridge_tbl]: add forgotten gl_get_current

* Clean[jre_launcher]: remove stray adrsp_test() declaration
This commit is contained in:
Maksim Belov
2023-11-06 23:12:08 +03:00
committed by GitHub
parent 9a24cdea20
commit 682fe04ef6
10 changed files with 274 additions and 142 deletions

View File

@@ -46,6 +46,7 @@ LOCAL_SRC_FILES := \
bigcoreaffinity.c \
egl_bridge.c \
ctxbridges/gl_bridge.c \
ctxbridges/osm_bridge.c \
ctxbridges/egl_loader.c \
ctxbridges/osmesa_loader.c \
environ/environ.c \
@@ -53,6 +54,7 @@ LOCAL_SRC_FILES := \
jre_launcher.c \
utils.c \
driver_helper/nsbypass.c
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
LOCAL_CFLAGS += -DADRENO_POSSIBLE
LOCAL_LDLIBS += -lEGL -lGLESv2

View File

@@ -0,0 +1,45 @@
//
// Created by maks on 18.10.2023.
//
#ifndef POJAVLAUNCHER_BRIDGE_TBL_H
#define POJAVLAUNCHER_BRIDGE_TBL_H
#include <ctxbridges/common.h>
#include <ctxbridges/gl_bridge.h>
#include <ctxbridges/osm_bridge.h>
typedef basic_render_window_t* (*br_init_context_t)(basic_render_window_t* share);
typedef void (*br_make_current_t)(basic_render_window_t* bundle);
typedef basic_render_window_t* (*br_get_current_t)();
bool (*br_init)() = NULL;
br_init_context_t br_init_context = NULL;
br_make_current_t br_make_current = NULL;
br_get_current_t br_get_current = NULL;
void (*br_swap_buffers)() = NULL;
void (*br_setup_window)() = NULL;
void (*br_swap_interval)(int swapInterval) = NULL;
void set_osm_bridge_tbl() {
br_init = osm_init;
br_init_context = (br_init_context_t) osm_init_context;
br_make_current = (br_make_current_t) osm_make_current;
br_get_current = (br_get_current_t) osm_get_current;
br_swap_buffers = osm_swap_buffers;
br_setup_window = osm_setup_window;
br_swap_interval = osm_swap_interval;
}
void set_gl_bridge_tbl() {
br_init = gl_init;
br_init_context = (br_init_context_t) gl_init_context;
br_make_current = (br_make_current_t) gl_make_current;
br_get_current = (br_get_current_t) gl_get_current;
br_swap_buffers = gl_swap_buffers;
br_setup_window = gl_setup_window;
br_swap_interval = gl_swap_interval;
}
#endif //POJAVLAUNCHER_BRIDGE_TBL_H

View File

@@ -0,0 +1,17 @@
//
// Created by maks on 18.10.2023.
//
#ifndef POJAVLAUNCHER_COMMON_H
#define POJAVLAUNCHER_COMMON_H
#define STATE_RENDERER_ALIVE 0
#define STATE_RENDERER_NEW_WINDOW 1
typedef struct {
char state;
struct ANativeWindow *nativeSurface;
struct ANativeWindow *newNativeSurface;
} basic_render_window_t;
#endif //POJAVLAUNCHER_COMMON_H

View File

@@ -15,10 +15,8 @@
// Created by maks on 17.09.2022.
//
#define STATE_RENDERER_ALIVE 0
#define STATE_RENDERER_NEW_WINDOW 1
static const char* g_LogTag = "GLBridge";
static __thread render_window_t* currentBundle;
static __thread gl_render_window_t* currentBundle;
static EGLDisplay g_EglDisplay;
bool gl_init() {
@@ -37,9 +35,13 @@ bool gl_init() {
return true;
}
render_window_t* gl_init_context(render_window_t *share) {
render_window_t* bundle = malloc(sizeof(render_window_t));
memset(bundle, 0, sizeof(render_window_t));
gl_render_window_t* gl_get_current() {
return currentBundle;
}
gl_render_window_t* gl_init_context(gl_render_window_t *share) {
gl_render_window_t* bundle = malloc(sizeof(gl_render_window_t));
memset(bundle, 0, sizeof(gl_render_window_t));
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_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE };
EGLint num_configs = 0;
@@ -86,7 +88,7 @@ render_window_t* gl_init_context(render_window_t *share) {
return bundle;
}
void gl_swap_surface(render_window_t* bundle) {
void gl_swap_surface(gl_render_window_t* bundle) {
if(bundle->nativeSurface != NULL) {
ANativeWindow_release(bundle->nativeSurface);
}
@@ -107,7 +109,7 @@ void gl_swap_surface(render_window_t* bundle) {
//eglMakeCurrent_p(g_EglDisplay, bundle->surface, bundle->surface, bundle->context);
}
void gl_make_current(render_window_t* bundle) {
void gl_make_current(gl_render_window_t* bundle) {
if(bundle == NULL) {
if(eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
currentBundle = NULL;
@@ -116,7 +118,7 @@ void gl_make_current(render_window_t* bundle) {
}
bool hasSetMainWindow = false;
if(pojav_environ->mainWindowBundle == NULL) {
pojav_environ->mainWindowBundle = bundle;
pojav_environ->mainWindowBundle = (basic_render_window_t*)bundle;
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is now %p", pojav_environ->mainWindowBundle);
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
hasSetMainWindow = true;
@@ -130,7 +132,7 @@ void gl_make_current(render_window_t* bundle) {
}else {
if(hasSetMainWindow) {
pojav_environ->mainWindowBundle->newNativeSurface = NULL;
gl_swap_surface(pojav_environ->mainWindowBundle);
gl_swap_surface((gl_render_window_t*)pojav_environ->mainWindowBundle);
pojav_environ->mainWindowBundle = NULL;
}
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglMakeCurrent returned with error: %04x", eglGetError_p());

View File

@@ -8,17 +8,18 @@
typedef struct {
char state;
struct ANativeWindow *nativeSurface;
struct ANativeWindow *newNativeSurface;
EGLConfig config;
EGLint format;
EGLContext context;
EGLSurface surface;
struct ANativeWindow *nativeSurface;
struct ANativeWindow *newNativeSurface;
} render_window_t;
} gl_render_window_t;
bool gl_init();
render_window_t* gl_init_context(render_window_t* share);
void gl_make_current(render_window_t* bundle);
gl_render_window_t* gl_get_current();
gl_render_window_t* gl_init_context(gl_render_window_t* share);
void gl_make_current(gl_render_window_t* bundle);
void gl_swap_buffers();
void gl_setup_window();
void gl_swap_interval(int swapInterval);

View File

@@ -0,0 +1,138 @@
//
// Created by maks on 18.10.2023.
//
#include <malloc.h>
#include <string.h>
#include <environ/environ.h>
#include <android/log.h>
#include "osm_bridge.h"
static const char* g_LogTag = "GLBridge";
static __thread osm_render_window_t* currentBundle;
// a tiny buffer for rendering when there's nowhere t render
static char no_render_buffer[4];
bool osm_init() {
dlsym_OSMesa();
return true; // no more specific initialization required
}
osm_render_window_t* osm_get_current() {
return currentBundle;
}
osm_render_window_t* osm_init_context(osm_render_window_t* share) {
osm_render_window_t* render_window = malloc(sizeof(osm_render_window_t));
if(render_window == NULL) return NULL;
memset(render_window, 0, sizeof(osm_render_window_t));
OSMesaContext osmesa_share = NULL;
if(share != NULL) osmesa_share = share->context;
OSMesaContext context = OSMesaCreateContext_p(GL_RGBA, osmesa_share);
if(context == NULL) {
free(render_window);
return NULL;
}
render_window->context = context;
return render_window;
}
void osm_set_no_render_buffer(ANativeWindow_Buffer* buffer) {
buffer->bits = &no_render_buffer;
buffer->width = 1;
buffer->height = 1;
buffer->stride = 0;
}
void osm_swap_surfaces(osm_render_window_t* bundle) {
if(bundle->nativeSurface != NULL && bundle->newNativeSurface != bundle->nativeSurface) {
if(!bundle->disable_rendering) {
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Unlocking for cleanup...");
ANativeWindow_unlockAndPost(bundle->nativeSurface);
}
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;
bundle->newNativeSurface = NULL;
ANativeWindow_acquire(bundle->nativeSurface);
ANativeWindow_setBuffersGeometry(bundle->nativeSurface, 0, 0, WINDOW_FORMAT_RGBX_8888);
bundle->disable_rendering = false;
return;
}else {
__android_log_print(ANDROID_LOG_ERROR, g_LogTag,
"No new native surface, switching to dummy framebuffer");
bundle->nativeSurface = NULL;
osm_set_no_render_buffer(&bundle->buffer);
bundle->disable_rendering = true;
}
}
void osm_release_window() {
currentBundle->newNativeSurface = NULL;
osm_swap_surfaces(currentBundle);
}
void osm_apply_current_ll() {
ANativeWindow_Buffer* buffer = &currentBundle->buffer;
OSMesaMakeCurrent_p(currentBundle->context, buffer->bits, GL_UNSIGNED_BYTE, buffer->width, buffer->height);
if(buffer->stride != currentBundle->last_stride)
OSMesaPixelStore_p(OSMESA_ROW_LENGTH, buffer->stride);
currentBundle->last_stride = buffer->stride;
}
void osm_make_current(osm_render_window_t* bundle) {
if(bundle == NULL) {
//technically this does nothing as its not possible to unbind a context in OSMesa
OSMesaMakeCurrent_p(NULL, NULL, 0, 0, 0);
currentBundle = NULL;
return;
}
bool hasSetMainWindow = false;
currentBundle = bundle;
if(pojav_environ->mainWindowBundle == NULL) {
pojav_environ->mainWindowBundle = (basic_render_window_t*) bundle;
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is now %p", pojav_environ->mainWindowBundle);
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
hasSetMainWindow = true;
}
if(bundle->nativeSurface == NULL) {
//prepare the buffer for our first render!
osm_swap_surfaces(bundle);
if(hasSetMainWindow) pojav_environ->mainWindowBundle->state = STATE_RENDERER_ALIVE;
}
osm_set_no_render_buffer(&bundle->buffer);
osm_apply_current_ll();
OSMesaPixelStore_p(OSMESA_Y_UP,0);
}
void osm_swap_buffers() {
if(currentBundle->state == STATE_RENDERER_NEW_WINDOW) {
osm_swap_surfaces(currentBundle);
currentBundle->state = STATE_RENDERER_ALIVE;
}
if(currentBundle->nativeSurface != NULL && !currentBundle->disable_rendering)
if(ANativeWindow_lock(currentBundle->nativeSurface, &currentBundle->buffer, NULL) != 0)
osm_release_window();
osm_apply_current_ll();
glFinish_p(); // this will force osmesa to write the last rendered image into the buffer
if(currentBundle->nativeSurface != NULL && !currentBundle->disable_rendering)
if(ANativeWindow_unlockAndPost(currentBundle->nativeSurface) != 0)
osm_release_window();
}
void osm_setup_window() {
if(pojav_environ->mainWindowBundle != NULL) {
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is not NULL, changing state");
pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
}
}
void osm_swap_interval(int swapInterval) {
// nothing, as you can only set the swap interval with internal system APIs
}

View File

@@ -0,0 +1,29 @@
//
// Created by maks on 18.10.2023.
//
#include <android/native_window.h>
#include <stdbool.h>
#ifndef POJAVLAUNCHER_OSM_BRIDGE_H
#define POJAVLAUNCHER_OSM_BRIDGE_H
#include "osmesa_loader.h"
typedef struct {
char state;
struct ANativeWindow *nativeSurface;
struct ANativeWindow *newNativeSurface;
ANativeWindow_Buffer buffer;
int32_t last_stride;
bool disable_rendering;
OSMesaContext context;
} osm_render_window_t;
bool osm_init();
osm_render_window_t* osm_get_current();
osm_render_window_t* osm_init_context(osm_render_window_t* share);
void osm_make_current(osm_render_window_t* bundle);
void osm_swap_buffers();
void osm_setup_window();
void osm_swap_interval(int swapInterval);
#endif //POJAVLAUNCHER_OSM_BRIDGE_H

View File

@@ -25,7 +25,8 @@
#include <environ/environ.h>
#include <android/dlext.h>
#include "utils.h"
#include "ctxbridges/gl_bridge.h"
#include "ctxbridges/bridge_tbl.h"
#include "ctxbridges/osm_bridge.h"
#define GLFW_CLIENT_API 0x22001
/* Consider GLFW_NO_API as Vulkan API */
@@ -83,9 +84,7 @@ EXTERNAL_API void pojavTerminate() {
JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_setupBridgeWindow(JNIEnv* env, ABI_COMPAT jclass clazz, jobject surface) {
pojav_environ->pojavWindow = ANativeWindow_fromSurface(env, surface);
if(pojav_environ->config_renderer == RENDERER_GL4ES) {
gl_setup_window();
}
if(br_setup_window != NULL) br_setup_window();
}
@@ -95,25 +94,7 @@ Java_net_kdt_pojavlaunch_utils_JREUtils_releaseBridgeWindow(ABI_COMPAT JNIEnv *e
}
EXTERNAL_API void* pojavGetCurrentContext() {
switch (pojav_environ->config_renderer) {
case RENDERER_GL4ES:
return (void *)eglGetCurrentContext_p();
case RENDERER_VK_ZINK:
return (void *)OSMesaGetCurrentContext_p();
default: return NULL;
}
}
void loadSymbols() {
switch (pojav_environ->config_renderer) {
case RENDERER_VK_ZINK:
dlsym_OSMesa();
break;
case RENDERER_GL4ES:
//inside glbridge
break;
}
return br_get_current();
}
//#define ADRENO_POSSIBLE
@@ -208,14 +189,6 @@ void load_vulkan() {
set_vulkan_ptr(vulkan_ptr);
}
EXTERNAL_API int pojavInit() {
ANativeWindow_acquire(pojav_environ->pojavWindow);
pojav_environ->savedWidth = ANativeWindow_getWidth(pojav_environ->pojavWindow);
pojav_environ->savedHeight = ANativeWindow_getHeight(pojav_environ->pojavWindow);
ANativeWindow_setBuffersGeometry(pojav_environ->pojavWindow,pojav_environ->savedWidth,pojav_environ->savedHeight,AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM);
return 1;
}
int pojavInitOpenGL() {
// Only affects GL4ES as of now
const char *forceVsync = getenv("FORCE_VSYNC");
@@ -226,30 +199,28 @@ int pojavInitOpenGL() {
const char *renderer = getenv("POJAV_RENDERER");
if (strncmp("opengles", renderer, 8) == 0) {
pojav_environ->config_renderer = RENDERER_GL4ES;
// Symbols are loaded inside gl_bridge
set_gl_bridge_tbl();
} else if (strcmp(renderer, "vulkan_zink") == 0) {
pojav_environ->config_renderer = RENDERER_VK_ZINK;
load_vulkan();
setenv("GALLIUM_DRIVER","zink",1);
loadSymbols();
set_osm_bridge_tbl();
}
if(pojav_environ->config_renderer == RENDERER_GL4ES) {
if(gl_init()) {
gl_setup_window();
return 1;
}
return 0;
if(br_init()) {
br_setup_window();
}
if (pojav_environ->config_renderer == RENDERER_VK_ZINK) {
if(OSMesaCreateContext_p == NULL) {
printf("OSMDroid: %s\n",dlerror());
return 0;
}
}
return 0;
}
EXTERNAL_API int pojavInit() {
ANativeWindow_acquire(pojav_environ->pojavWindow);
pojav_environ->savedWidth = ANativeWindow_getWidth(pojav_environ->pojavWindow);
pojav_environ->savedHeight = ANativeWindow_getHeight(pojav_environ->pojavWindow);
ANativeWindow_setBuffersGeometry(pojav_environ->pojavWindow,pojav_environ->savedWidth,pojav_environ->savedHeight,AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM);
pojavInitOpenGL();
return 1;
}
EXTERNAL_API void pojavSetWindowHint(int hint, int value) {
if (hint != GLFW_CLIENT_API) return;
switch (value) {
@@ -268,73 +239,20 @@ EXTERNAL_API void pojavSetWindowHint(int hint, int value) {
}
}
ANativeWindow_Buffer buf;
int32_t stride;
bool stopSwapBuffers;
void pojavSwapBuffers() {
if (stopSwapBuffers) {
return;
}
switch (pojav_environ->config_renderer) {
case RENDERER_GL4ES: {
gl_swap_buffers();
} break;
case RENDERER_VK_ZINK: {
OSMesaContext ctx = OSMesaGetCurrentContext_p();
if(ctx == NULL) {
printf("Zink: attempted to swap buffers without context!");
break;
}
OSMesaMakeCurrent_p(ctx,buf.bits,GL_UNSIGNED_BYTE,pojav_environ->savedWidth, pojav_environ->savedHeight);
glFinish_p();
ANativeWindow_unlockAndPost(pojav_environ->pojavWindow);
ANativeWindow_lock(pojav_environ->pojavWindow,&buf,NULL);
} break;
}
EXTERNAL_API void pojavSwapBuffers() {
br_swap_buffers();
}
EXTERNAL_API void pojavMakeCurrent(void* window) {
if(pojav_environ->config_renderer == RENDERER_GL4ES) {
gl_make_current((render_window_t*)window);
}
if (pojav_environ->config_renderer == RENDERER_VK_ZINK) {
printf("OSMDroid: making current %p\n", pojav_environ->pojavWindow);
ANativeWindow_lock(pojav_environ->pojavWindow,&buf,NULL);
OSMesaMakeCurrent_p((OSMesaContext)window,buf.bits,GL_UNSIGNED_BYTE,pojav_environ->savedWidth,pojav_environ->savedHeight);
OSMesaPixelStore_p(OSMESA_ROW_LENGTH,buf.stride);
OSMesaPixelStore_p(OSMESA_Y_UP,0);
printf("OSMDroid: vendor: %s\n",glGetString_p(GL_VENDOR));
printf("OSMDroid: renderer: %s\n",glGetString_p(GL_RENDERER));
glClearColor_p(0.4f, 0.4f, 0.4f, 1.0f);
glClear_p(GL_COLOR_BUFFER_BIT);
pojavSwapBuffers();
}
br_make_current((basic_render_window_t*)window);
}
EXTERNAL_API void* pojavCreateContext(void* contextSrc) {
if (pojav_environ->config_renderer == RENDERER_VULKAN) {
return (void *)pojav_environ->pojavWindow;
return (void *) pojav_environ->pojavWindow;
}
pojavInitOpenGL();
if (pojav_environ->config_renderer == RENDERER_GL4ES) {
return gl_init_context(contextSrc);
}
if (pojav_environ->config_renderer == RENDERER_VK_ZINK) {
printf("OSMDroid: generating context\n");
void* ctx = OSMesaCreateContext_p(OSMESA_RGBA,contextSrc);
printf("OSMDroid: context=%p\n",ctx);
return ctx;
}
printf("Unknown config_renderer value: %i\n", pojav_environ->config_renderer);
abort();
return br_init_context((basic_render_window_t*)contextSrc);
}
EXTERNAL_API JNIEXPORT jlong JNICALL
@@ -347,27 +265,7 @@ Java_org_lwjgl_vulkan_VK_getVulkanDriverHandle(ABI_COMPAT JNIEnv *env, ABI_COMPA
return strtoul(getenv("VULKAN_PTR"), NULL, 0x10);
}
EXTERNAL_API JNIEXPORT jlong JNICALL
Java_org_lwjgl_opengl_GL_getGraphicsBufferAddr(ABI_COMPAT JNIEnv *env, ABI_COMPAT jobject thiz) {
return (jlong) buf.bits;
}
EXTERNAL_API JNIEXPORT jintArray JNICALL
Java_org_lwjgl_opengl_GL_getNativeWidthHeight(JNIEnv *env, ABI_COMPAT jobject thiz) {
jintArray ret = (*env)->NewIntArray(env,2);
jint arr[] = {pojav_environ->savedWidth, pojav_environ->savedHeight};
(*env)->SetIntArrayRegion(env,ret,0,2,arr);
return ret;
}
EXTERNAL_API void pojavSwapInterval(int interval) {
switch (pojav_environ->config_renderer) {
case RENDERER_GL4ES: {
gl_swap_interval(interval);
} break;
case RENDERER_VK_ZINK: {
printf("eglSwapInterval: NOT IMPLEMENTED YET!\n");
// Nothing to do here
} break;
}
br_swap_interval(interval);
}

View File

@@ -5,7 +5,7 @@
#ifndef POJAVLAUNCHER_ENVIRON_H
#define POJAVLAUNCHER_ENVIRON_H
#include <ctxbridges/gl_bridge.h>
#include <ctxbridges/common.h>
#include <stdatomic.h>
#include <jni.h>
@@ -32,7 +32,7 @@ typedef void GLFW_invoke_WindowSize_func(void* window, int width, int height);
struct pojav_environ_s {
struct ANativeWindow* pojavWindow;
render_window_t* mainWindowBundle;
basic_render_window_t* mainWindowBundle;
int config_renderer;
bool force_vsync;
atomic_size_t eventCounter; // Count the number of events to be pumped out

View File

Binary file not shown.