Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/PojavLauncher
Path: blob/v3_openjdk/app_pojavlauncher/src/main/jni/egl_bridge.c
2128 views
1
#include <jni.h>
2
#include <assert.h>
3
#include <dlfcn.h>
4
5
#include <stdbool.h>
6
#include <stdint.h>
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <sys/types.h>
10
#include <unistd.h>
11
12
#include <EGL/egl.h>
13
#include <GL/osmesa.h>
14
#include "ctxbridges/osmesa_loader.h"
15
#include "driver_helper/nsbypass.h"
16
17
#ifdef GLES_TEST
18
#include <GLES2/gl2.h>
19
#endif
20
21
#include <android/native_window.h>
22
#include <android/native_window_jni.h>
23
#include <android/rect.h>
24
#include <string.h>
25
#include <environ/environ.h>
26
#include <android/dlext.h>
27
#include "utils.h"
28
#include "ctxbridges/bridge_tbl.h"
29
#include "ctxbridges/osm_bridge.h"
30
31
#define GLFW_CLIENT_API 0x22001
32
/* Consider GLFW_NO_API as Vulkan API */
33
#define GLFW_NO_API 0
34
#define GLFW_OPENGL_API 0x30001
35
36
// This means that the function is an external API and that it will be used
37
#define EXTERNAL_API __attribute__((used))
38
// This means that you are forced to have this function/variable for ABI compatibility
39
#define ABI_COMPAT __attribute__((unused))
40
41
42
struct PotatoBridge {
43
44
/* EGLContext */ void* eglContext;
45
/* EGLDisplay */ void* eglDisplay;
46
/* EGLSurface */ void* eglSurface;
47
/*
48
void* eglSurfaceRead;
49
void* eglSurfaceDraw;
50
*/
51
};
52
EGLConfig config;
53
struct PotatoBridge potatoBridge;
54
55
#include "ctxbridges/egl_loader.h"
56
#include "ctxbridges/osmesa_loader.h"
57
58
#define RENDERER_GL4ES 1
59
#define RENDERER_VK_ZINK 2
60
#define RENDERER_VULKAN 4
61
62
EXTERNAL_API void pojavTerminate() {
63
printf("EGLBridge: Terminating\n");
64
65
switch (pojav_environ->config_renderer) {
66
case RENDERER_GL4ES: {
67
eglMakeCurrent_p(potatoBridge.eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
68
eglDestroySurface_p(potatoBridge.eglDisplay, potatoBridge.eglSurface);
69
eglDestroyContext_p(potatoBridge.eglDisplay, potatoBridge.eglContext);
70
eglTerminate_p(potatoBridge.eglDisplay);
71
eglReleaseThread_p();
72
73
potatoBridge.eglContext = EGL_NO_CONTEXT;
74
potatoBridge.eglDisplay = EGL_NO_DISPLAY;
75
potatoBridge.eglSurface = EGL_NO_SURFACE;
76
} break;
77
78
//case RENDERER_VIRGL:
79
case RENDERER_VK_ZINK: {
80
// Nothing to do here
81
} break;
82
}
83
}
84
85
JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_setupBridgeWindow(JNIEnv* env, ABI_COMPAT jclass clazz, jobject surface) {
86
pojav_environ->pojavWindow = ANativeWindow_fromSurface(env, surface);
87
if(br_setup_window != NULL) br_setup_window();
88
}
89
90
91
JNIEXPORT void JNICALL
92
Java_net_kdt_pojavlaunch_utils_JREUtils_releaseBridgeWindow(ABI_COMPAT JNIEnv *env, ABI_COMPAT jclass clazz) {
93
ANativeWindow_release(pojav_environ->pojavWindow);
94
}
95
96
EXTERNAL_API void* pojavGetCurrentContext() {
97
return br_get_current();
98
}
99
100
//#define ADRENO_POSSIBLE
101
#ifdef ADRENO_POSSIBLE
102
void* load_turnip_vulkan() {
103
if(getenv("POJAV_LOAD_TURNIP") == NULL) return NULL;
104
const char* native_dir = getenv("POJAV_NATIVEDIR");
105
const char* cache_dir = getenv("TMPDIR");
106
if(!linker_ns_load(native_dir)) return NULL;
107
void* linkerhook = linker_ns_dlopen("liblinkerhook.so", RTLD_LOCAL | RTLD_NOW);
108
if(linkerhook == NULL) return NULL;
109
void* turnip_driver_handle = linker_ns_dlopen("libvulkan_freedreno.so", RTLD_LOCAL | RTLD_NOW);
110
if(turnip_driver_handle == NULL) {
111
printf("AdrenoSupp: Failed to load Turnip!\n%s\n", dlerror());
112
dlclose(linkerhook);
113
return NULL;
114
}
115
void* dl_android = linker_ns_dlopen("libdl_android.so", RTLD_LOCAL | RTLD_LAZY);
116
if(dl_android == NULL) {
117
dlclose(linkerhook);
118
dlclose(turnip_driver_handle);
119
return NULL;
120
}
121
void* android_get_exported_namespace = dlsym(dl_android, "android_get_exported_namespace");
122
void (*linkerhook_pass_handles)(void*, void*, void*) = dlsym(linkerhook, "app__pojav_linkerhook_pass_handles");
123
if(linkerhook_pass_handles == NULL || android_get_exported_namespace == NULL) {
124
dlclose(dl_android);
125
dlclose(linkerhook);
126
dlclose(turnip_driver_handle);
127
return NULL;
128
}
129
linkerhook_pass_handles(turnip_driver_handle, android_dlopen_ext, android_get_exported_namespace);
130
void* libvulkan = linker_ns_dlopen_unique(cache_dir, "libvulkan.so", RTLD_LOCAL | RTLD_NOW);
131
return libvulkan;
132
}
133
#endif
134
135
static void set_vulkan_ptr(void* ptr) {
136
char envval[64];
137
sprintf(envval, "%"PRIxPTR, (uintptr_t)ptr);
138
setenv("VULKAN_PTR", envval, 1);
139
}
140
141
void load_vulkan() {
142
if(android_get_device_api_level() >= 28) { // the loader does not support below that
143
#ifdef ADRENO_POSSIBLE
144
void* result = load_turnip_vulkan();
145
if(result != NULL) {
146
printf("AdrenoSupp: Loaded Turnip, loader address: %p\n", result);
147
set_vulkan_ptr(result);
148
return;
149
}
150
#endif
151
}
152
printf("OSMDroid: loading vulkan regularly...\n");
153
void* vulkan_ptr = dlopen("libvulkan.so", RTLD_LAZY | RTLD_LOCAL);
154
printf("OSMDroid: loaded vulkan, ptr=%p\n", vulkan_ptr);
155
set_vulkan_ptr(vulkan_ptr);
156
}
157
158
int pojavInitOpenGL() {
159
// Only affects GL4ES as of now
160
const char *forceVsync = getenv("FORCE_VSYNC");
161
if (strcmp(forceVsync, "true") == 0)
162
pojav_environ->force_vsync = true;
163
164
// NOTE: Override for now.
165
const char *renderer = getenv("POJAV_RENDERER");
166
if (strncmp("opengles", renderer, 8) == 0) {
167
pojav_environ->config_renderer = RENDERER_GL4ES;
168
set_gl_bridge_tbl();
169
} else if (strcmp(renderer, "vulkan_zink") == 0) {
170
pojav_environ->config_renderer = RENDERER_VK_ZINK;
171
load_vulkan();
172
setenv("GALLIUM_DRIVER","zink",1);
173
set_osm_bridge_tbl();
174
}
175
if(br_init()) {
176
br_setup_window();
177
}
178
return 0;
179
}
180
181
extern void updateMonitorSize(int width, int height);
182
183
EXTERNAL_API int pojavInit() {
184
pojav_environ->glfwThreadVmEnv = get_attached_env(pojav_environ->runtimeJavaVMPtr);
185
if(pojav_environ->glfwThreadVmEnv == NULL) {
186
printf("Failed to attach Java-side JNIEnv to GLFW thread\n");
187
return 0;
188
}
189
ANativeWindow_acquire(pojav_environ->pojavWindow);
190
pojav_environ->savedWidth = ANativeWindow_getWidth(pojav_environ->pojavWindow);
191
pojav_environ->savedHeight = ANativeWindow_getHeight(pojav_environ->pojavWindow);
192
ANativeWindow_setBuffersGeometry(pojav_environ->pojavWindow,pojav_environ->savedWidth,pojav_environ->savedHeight,AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM);
193
updateMonitorSize(pojav_environ->savedWidth, pojav_environ->savedHeight);
194
pojavInitOpenGL();
195
return 1;
196
}
197
198
EXTERNAL_API void pojavSetWindowHint(int hint, int value) {
199
if (hint != GLFW_CLIENT_API) return;
200
switch (value) {
201
case GLFW_NO_API:
202
pojav_environ->config_renderer = RENDERER_VULKAN;
203
/* Nothing to do: initialization is handled in Java-side */
204
// pojavInitVulkan();
205
break;
206
case GLFW_OPENGL_API:
207
/* Nothing to do: initialization is called in pojavCreateContext */
208
// pojavInitOpenGL();
209
break;
210
default:
211
printf("GLFW: Unimplemented API 0x%x\n", value);
212
abort();
213
}
214
}
215
216
EXTERNAL_API void pojavSwapBuffers() {
217
br_swap_buffers();
218
}
219
220
221
EXTERNAL_API void pojavMakeCurrent(void* window) {
222
br_make_current((basic_render_window_t*)window);
223
}
224
225
EXTERNAL_API void* pojavCreateContext(void* contextSrc) {
226
if (pojav_environ->config_renderer == RENDERER_VULKAN) {
227
return (void *) pojav_environ->pojavWindow;
228
}
229
return br_init_context((basic_render_window_t*)contextSrc);
230
}
231
232
void* maybe_load_vulkan() {
233
// We use the env var because
234
// 1. it's easier to do that
235
// 2. it won't break if something will try to load vulkan and osmesa simultaneously
236
if(getenv("VULKAN_PTR") == NULL) load_vulkan();
237
return (void*) strtoul(getenv("VULKAN_PTR"), NULL, 0x10);
238
}
239
240
EXTERNAL_API JNIEXPORT jlong JNICALL
241
Java_org_lwjgl_vulkan_VK_getVulkanDriverHandle(ABI_COMPAT JNIEnv *env, ABI_COMPAT jclass thiz) {
242
printf("EGLBridge: LWJGL-side Vulkan loader requested the Vulkan handle\n");
243
return (jlong) maybe_load_vulkan();
244
}
245
246
EXTERNAL_API void pojavSwapInterval(int interval) {
247
br_swap_interval(interval);
248
}
249
250
251