add support for virgl
This commit is contained in:
parent
5d3acf9804
commit
568f42015e
|
@ -66,6 +66,7 @@ LOCAL_SRC_FILES := \
|
|||
pojav/ctxbridges/swap_interval_no_egl.c \
|
||||
pojav/environ/environ.c \
|
||||
pojav/input_bridge_v3.c \
|
||||
pojav/virgl/virgl.c \
|
||||
driver_helper/nsbypass.c
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include "osmesa_loader.h"
|
||||
#include "pojav/environ/environ.h"
|
||||
#include "pojav/virgl/virgl.h"
|
||||
|
||||
GLboolean (*OSMesaMakeCurrent_p) (OSMesaContext ctx, void *buffer, GLenum type,
|
||||
GLsizei width, GLsizei height);
|
||||
|
@ -20,14 +22,15 @@ void (*glReadPixels_p) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum
|
|||
|
||||
void dlsym_OSMesa() {
|
||||
char* main_path = NULL;
|
||||
char* alt_path = NULL;
|
||||
if(asprintf(&main_path, "%s/libOSMesa_8.so", getenv("POJAV_NATIVEDIR")) == -1 ||
|
||||
asprintf(&alt_path, "%s/libOSMesa.so.8", getenv("POJAV_NATIVEDIR")) == -1) {
|
||||
char *fmt = "%s/libOSMesa_8.so";
|
||||
if (pojav_environ->config_renderer == RENDERER_VIRGL) {
|
||||
fmt = "%s/libOSMesa_81.so";
|
||||
}
|
||||
if (asprintf(&main_path, fmt, getenv("POJAV_NATIVEDIR")) == -1) {
|
||||
abort();
|
||||
}
|
||||
void* dl_handle = NULL;
|
||||
dl_handle = dlopen(alt_path, RTLD_GLOBAL);
|
||||
if(dl_handle == NULL) dl_handle = dlopen(main_path, RTLD_GLOBAL);
|
||||
dl_handle = dlopen(main_path, RTLD_GLOBAL);
|
||||
if(dl_handle == NULL) abort();
|
||||
OSMesaMakeCurrent_p = dlsym(dl_handle, "OSMesaMakeCurrent");
|
||||
OSMesaGetCurrentContext_p = dlsym(dl_handle,"OSMesaGetCurrentContext");
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "pojav/egl_bridge.h"
|
||||
#include <jni.h>
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
|
@ -37,22 +38,12 @@
|
|||
// This means that you are forced to have this function/variable for ABI compatibility
|
||||
#define ABI_COMPAT __attribute__((unused))
|
||||
|
||||
|
||||
struct PotatoBridge {
|
||||
|
||||
/* EGLContext */ void* eglContext;
|
||||
/* EGLDisplay */ void* eglDisplay;
|
||||
/* EGLSurface */ void* eglSurface;
|
||||
/*
|
||||
void* eglSurfaceRead;
|
||||
void* eglSurfaceDraw;
|
||||
*/
|
||||
};
|
||||
EGLConfig config;
|
||||
struct PotatoBridge potatoBridge;
|
||||
|
||||
#include "ctxbridges/egl_loader.h"
|
||||
#include "ctxbridges/osmesa_loader.h"
|
||||
#include "pojav/virgl/virgl.h"
|
||||
|
||||
#define RENDERER_GL4ES 1
|
||||
#define RENDERER_VK_ZINK 2
|
||||
|
@ -94,6 +85,9 @@ Java_net_kdt_pojavlaunch_utils_JREUtils_releaseBridgeWindow(ABI_COMPAT JNIEnv *e
|
|||
}
|
||||
|
||||
EXTERNAL_API void* pojavGetCurrentContext() {
|
||||
if (pojav_environ->config_renderer == RENDERER_VIRGL) {
|
||||
return virglGetCurrentContext();
|
||||
}
|
||||
return br_get_current();
|
||||
}
|
||||
|
||||
|
@ -197,7 +191,12 @@ int pojavInitOpenGL() {
|
|||
|
||||
// NOTE: Override for now.
|
||||
const char *renderer = getenv("POJAV_RENDERER");
|
||||
if (strncmp("opengles", renderer, 8) == 0) {
|
||||
if (strcmp(renderer, "opengles3_virgl") == 0) {
|
||||
pojav_environ->config_renderer = RENDERER_VIRGL;
|
||||
loadSymbolsVirGL();
|
||||
virglInit();
|
||||
return 0;
|
||||
} else if (strncmp("opengles", renderer, 8) == 0) {
|
||||
pojav_environ->config_renderer = RENDERER_GL4ES;
|
||||
set_gl_bridge_tbl();
|
||||
} else if (strcmp(renderer, "vulkan_zink") == 0) {
|
||||
|
@ -240,17 +239,28 @@ EXTERNAL_API void pojavSetWindowHint(int hint, int value) {
|
|||
}
|
||||
|
||||
EXTERNAL_API void pojavSwapBuffers() {
|
||||
br_swap_buffers();
|
||||
if (pojav_environ->config_renderer == RENDERER_VIRGL) {
|
||||
virglSwapBuffers();
|
||||
} else {
|
||||
br_swap_buffers();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EXTERNAL_API void pojavMakeCurrent(void* window) {
|
||||
br_make_current((basic_render_window_t*)window);
|
||||
if (pojav_environ->config_renderer == RENDERER_VIRGL)
|
||||
{
|
||||
virglMakeCurrent(window);
|
||||
} else {
|
||||
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;
|
||||
} else if (pojav_environ->config_renderer == RENDERER_VIRGL) {
|
||||
return virglCreateContext(contextSrc);
|
||||
}
|
||||
return br_init_context((basic_render_window_t*)contextSrc);
|
||||
}
|
||||
|
@ -266,6 +276,10 @@ Java_org_lwjgl_vulkan_VK_getVulkanDriverHandle(ABI_COMPAT JNIEnv *env, ABI_COMPA
|
|||
}
|
||||
|
||||
EXTERNAL_API void pojavSwapInterval(int interval) {
|
||||
br_swap_interval(interval);
|
||||
if (pojav_environ->config_renderer == RENDERER_VIRGL) {
|
||||
virglSwapInterval(interval);
|
||||
} else {
|
||||
br_swap_interval(interval);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Created by mio on 2024/8/20.
|
||||
//
|
||||
|
||||
#ifndef FOLD_CRAFT_LAUNCHER_EGL_BRIDGE_H
|
||||
#define FOLD_CRAFT_LAUNCHER_EGL_BRIDGE_H
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
struct PotatoBridge {
|
||||
|
||||
/* EGLContext */ void* eglContext;
|
||||
/* EGLDisplay */ void* eglDisplay;
|
||||
/* EGLSurface */ void* eglSurface;
|
||||
/*
|
||||
void* eglSurfaceRead;
|
||||
void* eglSurfaceDraw;
|
||||
*/
|
||||
};
|
||||
extern EGLConfig config;
|
||||
extern struct PotatoBridge potatoBridge;
|
||||
|
||||
#endif //FOLD_CRAFT_LAUNCHER_EGL_BRIDGE_H
|
|
@ -0,0 +1,192 @@
|
|||
//
|
||||
// Created by mio on 2024/8/20.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include "virgl.h"
|
||||
#include "pojav/environ/environ.h"
|
||||
#include "pojav/ctxbridges/osm_bridge.h"
|
||||
#include "pojav/egl_bridge.h"
|
||||
#include "pojav/ctxbridges/egl_loader.h"
|
||||
|
||||
#define RENDERER_VIRGL 3
|
||||
|
||||
int (*vtest_main_p)(int argc, char **argv);
|
||||
|
||||
void (*vtest_swap_buffers_p)(void);
|
||||
|
||||
void *virglGetCurrentContext() {
|
||||
return (void *) OSMesaGetCurrentContext_p();
|
||||
}
|
||||
|
||||
void virglSwapBuffers() {
|
||||
glFinish_p();
|
||||
vtest_swap_buffers_p();
|
||||
}
|
||||
|
||||
void virglMakeCurrent(void *window) {
|
||||
printf("OSMDroid: making current\n");
|
||||
OSMesaMakeCurrent_p((OSMesaContext) window,
|
||||
setbuffer,
|
||||
GL_UNSIGNED_BYTE,
|
||||
pojav_environ->savedWidth,
|
||||
pojav_environ->savedHeight);
|
||||
|
||||
printf("OSMDroid: vendor: %s\n", glGetString_p(GL_VENDOR));
|
||||
printf("OSMDroid: renderer: %s\n", glGetString_p(GL_RENDERER));
|
||||
glClear_p(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor_p(0.4f, 0.4f, 0.4f, 1.0f);
|
||||
|
||||
// Trigger a texture creation, which then set VIRGL_TEXTURE_ID
|
||||
int pixelsArr[4];
|
||||
glReadPixels_p(0, 0, 1, 1, GL_RGB, GL_INT, &pixelsArr);
|
||||
|
||||
virglSwapBuffers();
|
||||
}
|
||||
|
||||
void *virglCreateContext(void *contextSrc) {
|
||||
printf("OSMDroid: generating context\n");
|
||||
void *ctx = OSMesaCreateContext_p(OSMESA_RGBA, contextSrc);
|
||||
printf("OSMDroid: context=%p\n", ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void loadSymbolsVirGL() {
|
||||
dlsym_OSMesa();
|
||||
dlsym_EGL();
|
||||
|
||||
char *fileName = calloc(1, 1024);
|
||||
|
||||
sprintf(fileName, "%s/libvirgl_test_server.so", getenv("POJAV_NATIVEDIR"));
|
||||
void *handle = dlopen(fileName, RTLD_LAZY);
|
||||
printf("VirGL: libvirgl_test_server = %p\n", handle);
|
||||
if (!handle) {
|
||||
printf("VirGL: %s\n", dlerror());
|
||||
}
|
||||
vtest_main_p = dlsym(handle, "vtest_main");
|
||||
vtest_swap_buffers_p = dlsym(handle, "vtest_swap_buffers");
|
||||
|
||||
free(fileName);
|
||||
}
|
||||
|
||||
void *egl_make_current(void *window) {
|
||||
EGLBoolean success = eglMakeCurrent_p(
|
||||
potatoBridge.eglDisplay,
|
||||
window == 0 ? (EGLSurface *) 0 : potatoBridge.eglSurface,
|
||||
window == 0 ? (EGLSurface *) 0 : potatoBridge.eglSurface,
|
||||
/* window==0 ? EGL_NO_CONTEXT : */ (EGLContext *) window
|
||||
);
|
||||
|
||||
if (success == EGL_FALSE) {
|
||||
printf("EGLBridge: Error: eglMakeCurrent() failed: %p\n", eglGetError_p());
|
||||
} else {
|
||||
printf("EGLBridge: eglMakeCurrent() succeed!\n");
|
||||
}
|
||||
|
||||
if (pojav_environ->config_renderer == RENDERER_VIRGL) {
|
||||
printf("VirGL: vtest_main = %p\n", vtest_main_p);
|
||||
printf("VirGL: Calling VTest server's main function\n");
|
||||
vtest_main_p(3, (const char *[]) {"vtest", "--no-loop-or-fork", "--use-gles", NULL, NULL});
|
||||
}
|
||||
}
|
||||
|
||||
void virglSwapInterval(int interval) {
|
||||
eglSwapInterval_p(potatoBridge.eglDisplay, interval);
|
||||
}
|
||||
|
||||
int virglInit() {
|
||||
if (potatoBridge.eglDisplay == NULL || potatoBridge.eglDisplay == EGL_NO_DISPLAY) {
|
||||
potatoBridge.eglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);
|
||||
if (potatoBridge.eglDisplay == EGL_NO_DISPLAY) {
|
||||
printf("EGLBridge: Error eglGetDefaultDisplay() failed: %p\n", eglGetError_p());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("EGLBridge: Initializing\n");
|
||||
// printf("EGLBridge: ANativeWindow pointer = %p\n", pojav_environ->pojavWindow);
|
||||
//(*env)->ThrowNew(env,(*env)->FindClass(env,"java/lang/Exception"),"Trace exception");
|
||||
if (!eglInitialize_p(potatoBridge.eglDisplay, NULL, NULL)) {
|
||||
printf("EGLBridge: Error eglInitialize() failed: %s\n", eglGetError_p());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const EGLint attribs[] = {
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
// Minecraft required on initial 24
|
||||
EGL_DEPTH_SIZE, 24,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLint num_configs;
|
||||
EGLint vid;
|
||||
|
||||
if (!eglChooseConfig_p(potatoBridge.eglDisplay, attribs, &config, 1, &num_configs)) {
|
||||
printf("EGLBridge: Error couldn't get an EGL visual config: %s\n", eglGetError_p());
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(config);
|
||||
assert(num_configs > 0);
|
||||
|
||||
if (!eglGetConfigAttrib_p(potatoBridge.eglDisplay, config, EGL_NATIVE_VISUAL_ID, &vid)) {
|
||||
printf("EGLBridge: Error eglGetConfigAttrib() failed: %s\n", eglGetError_p());
|
||||
return 0;
|
||||
}
|
||||
|
||||
ANativeWindow_setBuffersGeometry(pojav_environ->pojavWindow, 0, 0, vid);
|
||||
|
||||
eglBindAPI_p(EGL_OPENGL_ES_API);
|
||||
|
||||
potatoBridge.eglSurface = eglCreateWindowSurface_p(potatoBridge.eglDisplay, config,
|
||||
pojav_environ->pojavWindow, NULL);
|
||||
|
||||
if (!potatoBridge.eglSurface) {
|
||||
printf("EGLBridge: Error eglCreateWindowSurface failed: %p\n", eglGetError_p());
|
||||
//(*env)->ThrowNew(env,(*env)->FindClass(env,"java/lang/Exception"),"Trace exception");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// sanity checks
|
||||
{
|
||||
EGLint val;
|
||||
assert(eglGetConfigAttrib_p(potatoBridge.eglDisplay, config, EGL_SURFACE_TYPE, &val));
|
||||
assert(val & EGL_WINDOW_BIT);
|
||||
}
|
||||
|
||||
printf("EGLBridge: Initialized!\n");
|
||||
printf("EGLBridge: ThreadID=%d\n", gettid());
|
||||
printf("EGLBridge: EGLDisplay=%p, EGLSurface=%p\n",
|
||||
/* window==0 ? EGL_NO_CONTEXT : */
|
||||
potatoBridge.eglDisplay,
|
||||
potatoBridge.eglSurface
|
||||
);
|
||||
|
||||
// Init EGL context and vtest server
|
||||
const EGLint ctx_attribs[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 3,
|
||||
EGL_NONE
|
||||
};
|
||||
EGLContext *ctx = eglCreateContext_p(potatoBridge.eglDisplay, config, NULL, ctx_attribs);
|
||||
printf("VirGL: created EGL context %p\n", ctx);
|
||||
|
||||
pthread_t t;
|
||||
pthread_create(&t, NULL, egl_make_current, (void *) ctx);
|
||||
usleep(100 * 1000); // need enough time for the server to init
|
||||
|
||||
if (OSMesaCreateContext_p == NULL) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "测试", "null");
|
||||
printf("OSMDroid: %s\n", dlerror());
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Created by mio on 2024/8/20.
|
||||
//
|
||||
|
||||
#ifndef FOLD_CRAFT_LAUNCHER_VIRGL_H
|
||||
#define FOLD_CRAFT_LAUNCHER_VIRGL_H
|
||||
|
||||
#define RENDERER_VIRGL 3
|
||||
|
||||
void* virglGetCurrentContext();
|
||||
void loadSymbolsVirGL();
|
||||
int virglInit();
|
||||
void virglSwapBuffers();
|
||||
void virglMakeCurrent(void* window);
|
||||
void* virglCreateContext(void* contextSrc);
|
||||
void virglSwapInterval(int interval);
|
||||
|
||||
#endif //FOLD_CRAFT_LAUNCHER_VIRGL_H
|
Loading…
Reference in New Issue