Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/PojavLauncher
Path: blob/v3_openjdk/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c
2128 views
1
#include <EGL/egl.h>
2
#include <android/native_window.h>
3
#include <android/native_window_jni.h>
4
#include <string.h>
5
#include <malloc.h>
6
#include <stdlib.h>
7
#include <dlfcn.h>
8
#include <stdbool.h>
9
#include <environ/environ.h>
10
#include "gl_bridge.h"
11
#include "egl_loader.h"
12
13
#define TAG __FILE_NAME__
14
#include <log.h>
15
16
//
17
// Created by maks on 17.09.2022.
18
//
19
20
static __thread gl_render_window_t* currentBundle;
21
static EGLDisplay g_EglDisplay;
22
23
bool gl_init() {
24
if(!dlsym_EGL()) return false;
25
g_EglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);
26
if (g_EglDisplay == EGL_NO_DISPLAY) {
27
LOGE("%s", "eglGetDisplay_p(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY");
28
return false;
29
}
30
if (eglInitialize_p(g_EglDisplay, 0, 0) != EGL_TRUE) {
31
LOGE("eglInitialize_p() failed: %04x", eglGetError_p());
32
return false;
33
}
34
return true;
35
}
36
37
gl_render_window_t* gl_get_current() {
38
return currentBundle;
39
}
40
41
static void gl4esi_get_display_dimensions(int* width, int* height) {
42
if(currentBundle == NULL) goto zero;
43
EGLSurface surface = currentBundle->surface;
44
// Fetch dimensions from the EGL surface - the most reliable way
45
EGLBoolean result_width = eglQuerySurface_p(g_EglDisplay, surface, EGL_WIDTH, width);
46
EGLBoolean result_height = eglQuerySurface_p(g_EglDisplay, surface, EGL_HEIGHT, height);
47
if(!result_width || !result_height) goto zero;
48
return;
49
50
zero:
51
// No idea what to do, but feeding gl4es incorrect or non-initialized dimensions may be
52
// a bad idea. Set to zero in case of errors.
53
*width = 0;
54
*height = 0;
55
}
56
57
gl_render_window_t* gl_init_context(gl_render_window_t *share) {
58
gl_render_window_t* bundle = malloc(sizeof(gl_render_window_t));
59
memset(bundle, 0, sizeof(gl_render_window_t));
60
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 };
61
EGLint num_configs = 0;
62
63
if (eglChooseConfig_p(g_EglDisplay, egl_attributes, NULL, 0, &num_configs) != EGL_TRUE) {
64
LOGE("eglChooseConfig_p() failed: %04x", eglGetError_p());
65
free(bundle);
66
return NULL;
67
}
68
if (num_configs == 0) {
69
LOGE("%s", "eglChooseConfig_p() found no matching config");
70
free(bundle);
71
return NULL;
72
}
73
74
// Get the first matching config
75
eglChooseConfig_p(g_EglDisplay, egl_attributes, &bundle->config, 1, &num_configs);
76
eglGetConfigAttrib_p(g_EglDisplay, bundle->config, EGL_NATIVE_VISUAL_ID, &bundle->format);
77
78
{
79
EGLBoolean bindResult;
80
if (strncmp(getenv("POJAV_RENDERER"), "opengles3_desktopgl", 19) == 0) {
81
printf("EGLBridge: Binding to desktop OpenGL\n");
82
bindResult = eglBindAPI_p(EGL_OPENGL_API);
83
} else {
84
printf("EGLBridge: Binding to OpenGL ES\n");
85
bindResult = eglBindAPI_p(EGL_OPENGL_ES_API);
86
}
87
if (!bindResult) printf("EGLBridge: bind failed: %p\n", eglGetError_p());
88
}
89
90
int libgl_es = strtol(getenv("LIBGL_ES"), NULL, 0);
91
if(libgl_es < 0 || libgl_es > INT16_MAX) libgl_es = 2;
92
const EGLint egl_context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, libgl_es, EGL_NONE };
93
bundle->context = eglCreateContext_p(g_EglDisplay, bundle->config, share == NULL ? EGL_NO_CONTEXT : share->context, egl_context_attributes);
94
95
if (bundle->context == EGL_NO_CONTEXT) {
96
LOGE("eglCreateContext_p() finished with error: %04x", eglGetError_p());
97
free(bundle);
98
return NULL;
99
}
100
return bundle;
101
}
102
103
void gl_swap_surface(gl_render_window_t* bundle) {
104
if(bundle->nativeSurface != NULL) {
105
ANativeWindow_release(bundle->nativeSurface);
106
}
107
if(bundle->surface != NULL) eglDestroySurface_p(g_EglDisplay, bundle->surface);
108
if(bundle->newNativeSurface != NULL) {
109
LOGI("Switching to new native surface");
110
bundle->nativeSurface = bundle->newNativeSurface;
111
bundle->newNativeSurface = NULL;
112
ANativeWindow_acquire(bundle->nativeSurface);
113
ANativeWindow_setBuffersGeometry(bundle->nativeSurface, 0, 0, bundle->format);
114
bundle->surface = eglCreateWindowSurface_p(g_EglDisplay, bundle->config, bundle->nativeSurface, NULL);
115
}else{
116
LOGI("No new native surface, switching to 1x1 pbuffer");
117
bundle->nativeSurface = NULL;
118
const EGLint pbuffer_attrs[] = {EGL_WIDTH, 1 , EGL_HEIGHT, 1, EGL_NONE};
119
bundle->surface = eglCreatePbufferSurface_p(g_EglDisplay, bundle->config, pbuffer_attrs);
120
}
121
//eglMakeCurrent_p(g_EglDisplay, bundle->surface, bundle->surface, bundle->context);
122
}
123
124
void gl_make_current(gl_render_window_t* bundle) {
125
126
if(bundle == NULL) {
127
if(eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
128
currentBundle = NULL;
129
}
130
return;
131
}
132
bool hasSetMainWindow = false;
133
if(pojav_environ->mainWindowBundle == NULL) {
134
pojav_environ->mainWindowBundle = (basic_render_window_t*)bundle;
135
LOGI("Main window bundle is now %p", pojav_environ->mainWindowBundle);
136
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
137
hasSetMainWindow = true;
138
}
139
LOGI("Making current, surface=%p, nativeSurface=%p, newNativeSurface=%p", bundle->surface, bundle->nativeSurface, bundle->newNativeSurface);
140
if(bundle->surface == NULL) { //it likely will be on the first run
141
gl_swap_surface(bundle);
142
}
143
if(eglMakeCurrent_p(g_EglDisplay, bundle->surface, bundle->surface, bundle->context)) {
144
currentBundle = bundle;
145
}else {
146
if(hasSetMainWindow) {
147
pojav_environ->mainWindowBundle->newNativeSurface = NULL;
148
gl_swap_surface((gl_render_window_t*)pojav_environ->mainWindowBundle);
149
pojav_environ->mainWindowBundle = NULL;
150
}
151
LOGE("eglMakeCurrent returned with error: %04x", eglGetError_p());
152
}
153
154
}
155
156
void gl_swap_buffers() {
157
if(currentBundle->state == STATE_RENDERER_NEW_WINDOW) {
158
eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); //detach everything to destroy the old EGLSurface
159
gl_swap_surface(currentBundle);
160
eglMakeCurrent_p(g_EglDisplay, currentBundle->surface, currentBundle->surface, currentBundle->context);
161
currentBundle->state = STATE_RENDERER_ALIVE;
162
}
163
if(currentBundle->surface != NULL)
164
if(!eglSwapBuffers_p(g_EglDisplay, currentBundle->surface) && eglGetError_p() == EGL_BAD_SURFACE) {
165
eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
166
currentBundle->newNativeSurface = NULL;
167
gl_swap_surface(currentBundle);
168
eglMakeCurrent_p(g_EglDisplay, currentBundle->surface, currentBundle->surface, currentBundle->context);
169
LOGI("The window has died, awaiting window change");
170
}
171
172
}
173
174
void gl_setup_window() {
175
if(pojav_environ->mainWindowBundle != NULL) {
176
LOGI("Main window bundle is not NULL, changing state");
177
pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
178
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
179
}
180
}
181
182
void gl_swap_interval(int swapInterval) {
183
if(pojav_environ->force_vsync) swapInterval = 1;
184
185
eglSwapInterval_p(g_EglDisplay, swapInterval);
186
}
187
188
JNIEXPORT void JNICALL
189
Java_org_lwjgl_opengl_PojavRendererInit_nativeInitGl4esInternals(JNIEnv *env, jclass clazz,
190
jobject function_provider) {
191
LOGI("GL4ES internals initializing...");
192
jclass funcProviderClass = (*env)->GetObjectClass(env, function_provider);
193
jmethodID method_getFunctionAddress = (*env)->GetMethodID(env, funcProviderClass, "getFunctionAddress", "(Ljava/lang/CharSequence;)J");
194
#define GETSYM(N) ((*env)->CallLongMethod(env, function_provider, method_getFunctionAddress, (*env)->NewStringUTF(env, N)));
195
196
void (*set_getmainfbsize)(void (*new_getMainFBSize)(int* width, int* height)) = (void*)GETSYM("set_getmainfbsize");
197
if(set_getmainfbsize != NULL) {
198
LOGI("GL4ES internals initialized dimension callback");
199
set_getmainfbsize(gl4esi_get_display_dimensions);
200
}
201
202
#undef GETSYM
203
}
204
205