Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/PojavLauncher
Path: blob/v3_openjdk/app_pojavlauncher/src/main/jni/ctxbridges/osm_bridge.c
2128 views
1
//
2
// Created by maks on 18.10.2023.
3
//
4
#include <malloc.h>
5
#include <string.h>
6
#include <environ/environ.h>
7
#include "osm_bridge.h"
8
#define TAG __FILE_NAME__
9
#include <log.h>
10
11
static __thread osm_render_window_t* currentBundle;
12
// a tiny buffer for rendering when there's nowhere t render
13
static char no_render_buffer[4];
14
15
// Its not in a .h file because it is not supposed to be used outsife of this file.
16
void setNativeWindowSwapInterval(struct ANativeWindow* nativeWindow, int swapInterval);
17
18
bool osm_init() {
19
if(!dlsym_OSMesa()) return false;
20
return true;
21
}
22
23
osm_render_window_t* osm_get_current() {
24
return currentBundle;
25
}
26
27
osm_render_window_t* osm_init_context(osm_render_window_t* share) {
28
osm_render_window_t* render_window = malloc(sizeof(osm_render_window_t));
29
if(render_window == NULL) return NULL;
30
memset(render_window, 0, sizeof(osm_render_window_t));
31
OSMesaContext osmesa_share = NULL;
32
if(share != NULL) osmesa_share = share->context;
33
OSMesaContext context = OSMesaCreateContext_p(GL_RGBA, osmesa_share);
34
if(context == NULL) {
35
free(render_window);
36
return NULL;
37
}
38
render_window->context = context;
39
return render_window;
40
}
41
42
void osm_set_no_render_buffer(ANativeWindow_Buffer* buffer) {
43
buffer->bits = &no_render_buffer;
44
buffer->width = 1;
45
buffer->height = 1;
46
buffer->stride = 0;
47
}
48
49
void osm_swap_surfaces(osm_render_window_t* bundle) {
50
if(bundle->nativeSurface != NULL && bundle->newNativeSurface != bundle->nativeSurface) {
51
if(!bundle->disable_rendering) {
52
LOGI("Unlocking for cleanup...");
53
ANativeWindow_unlockAndPost(bundle->nativeSurface);
54
}
55
ANativeWindow_release(bundle->nativeSurface);
56
}
57
if(bundle->newNativeSurface != NULL) {
58
LOGI("Switching to new native surface");
59
bundle->nativeSurface = bundle->newNativeSurface;
60
bundle->newNativeSurface = NULL;
61
ANativeWindow_acquire(bundle->nativeSurface);
62
ANativeWindow_setBuffersGeometry(bundle->nativeSurface, 0, 0, WINDOW_FORMAT_RGBX_8888);
63
bundle->disable_rendering = false;
64
return;
65
}else {
66
LOGI("No new native surface, switching to dummy framebuffer");
67
bundle->nativeSurface = NULL;
68
osm_set_no_render_buffer(&bundle->buffer);
69
bundle->disable_rendering = true;
70
}
71
72
}
73
74
void osm_release_window() {
75
currentBundle->newNativeSurface = NULL;
76
osm_swap_surfaces(currentBundle);
77
}
78
79
void osm_apply_current_ll() {
80
ANativeWindow_Buffer* buffer = &currentBundle->buffer;
81
OSMesaMakeCurrent_p(currentBundle->context, buffer->bits, GL_UNSIGNED_BYTE, buffer->width, buffer->height);
82
if(buffer->stride != currentBundle->last_stride)
83
OSMesaPixelStore_p(OSMESA_ROW_LENGTH, buffer->stride);
84
currentBundle->last_stride = buffer->stride;
85
}
86
87
void osm_make_current(osm_render_window_t* bundle) {
88
if(bundle == NULL) {
89
//technically this does nothing as its not possible to unbind a context in OSMesa
90
OSMesaMakeCurrent_p(NULL, NULL, 0, 0, 0);
91
currentBundle = NULL;
92
return;
93
}
94
bool hasSetMainWindow = false;
95
currentBundle = bundle;
96
if(pojav_environ->mainWindowBundle == NULL) {
97
pojav_environ->mainWindowBundle = (basic_render_window_t*) bundle;
98
LOGI("Main window bundle is now %p", pojav_environ->mainWindowBundle);
99
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
100
hasSetMainWindow = true;
101
}
102
if(bundle->nativeSurface == NULL) {
103
//prepare the buffer for our first render!
104
osm_swap_surfaces(bundle);
105
if(hasSetMainWindow) pojav_environ->mainWindowBundle->state = STATE_RENDERER_ALIVE;
106
}
107
osm_set_no_render_buffer(&bundle->buffer);
108
osm_apply_current_ll();
109
OSMesaPixelStore_p(OSMESA_Y_UP,0);
110
}
111
112
void osm_swap_buffers() {
113
if(currentBundle->state == STATE_RENDERER_NEW_WINDOW) {
114
osm_swap_surfaces(currentBundle);
115
currentBundle->state = STATE_RENDERER_ALIVE;
116
}
117
118
if(currentBundle->nativeSurface != NULL && !currentBundle->disable_rendering)
119
if(ANativeWindow_lock(currentBundle->nativeSurface, &currentBundle->buffer, NULL) != 0)
120
osm_release_window();
121
122
osm_apply_current_ll();
123
glFinish_p(); // this will force osmesa to write the last rendered image into the buffer
124
125
if(currentBundle->nativeSurface != NULL && !currentBundle->disable_rendering)
126
if(ANativeWindow_unlockAndPost(currentBundle->nativeSurface) != 0)
127
osm_release_window();
128
}
129
130
void osm_setup_window() {
131
if(pojav_environ->mainWindowBundle != NULL) {
132
LOGI("Main window bundle is not NULL, changing state");
133
pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
134
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
135
}
136
}
137
138
void osm_swap_interval(int swapInterval) {
139
if(pojav_environ->mainWindowBundle != NULL && pojav_environ->mainWindowBundle->nativeSurface != NULL) {
140
setNativeWindowSwapInterval(pojav_environ->mainWindowBundle->nativeSurface, swapInterval);
141
}
142
}
143