mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Fix] (trace-replay): validate OpenRA on both backends
This commit is contained in:
@@ -16,6 +16,7 @@ using PfnEglBindApi = EGLBoolean (*)(EGLenum);
|
||||
using PfnEglChooseConfig = EGLBoolean (*)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *);
|
||||
using PfnEglCreateContext = EGLContext (*)(EGLDisplay, EGLConfig, EGLContext, const EGLint *);
|
||||
using PfnEglCreatePbufferSurface = EGLSurface (*)(EGLDisplay, EGLConfig, const EGLint *);
|
||||
using PfnEglCreateWindowSurface = EGLSurface (*)(EGLDisplay, EGLConfig, EGLNativeWindowType, const EGLint *);
|
||||
using PfnEglDestroyContext = EGLBoolean (*)(EGLDisplay, EGLContext);
|
||||
using PfnEglDestroySurface = EGLBoolean (*)(EGLDisplay, EGLSurface);
|
||||
using PfnEglGetConfigAttrib = EGLBoolean (*)(EGLDisplay, EGLConfig, EGLint, EGLint *);
|
||||
@@ -26,12 +27,14 @@ using PfnEglMakeCurrent = EGLBoolean (*)(EGLDisplay, EGLSurface, EGLSurface, EGL
|
||||
using PfnEglQueryString = const char *(*)(EGLDisplay, EGLint);
|
||||
using PfnEglSwapBuffers = EGLBoolean (*)(EGLDisplay, EGLSurface);
|
||||
using PfnEglTerminate = EGLBoolean (*)(EGLDisplay);
|
||||
using PfnGlGetString = const unsigned char *(*)(unsigned int);
|
||||
|
||||
struct EglFns {
|
||||
PfnEglBindApi bindApi = nullptr;
|
||||
PfnEglChooseConfig chooseConfig = nullptr;
|
||||
PfnEglCreateContext createContext = nullptr;
|
||||
PfnEglCreatePbufferSurface createPbufferSurface = nullptr;
|
||||
PfnEglCreateWindowSurface createWindowSurface = nullptr;
|
||||
PfnEglDestroyContext destroyContext = nullptr;
|
||||
PfnEglDestroySurface destroySurface = nullptr;
|
||||
PfnEglGetConfigAttrib getConfigAttrib = nullptr;
|
||||
@@ -44,13 +47,39 @@ struct EglFns {
|
||||
PfnEglTerminate terminate = nullptr;
|
||||
};
|
||||
|
||||
struct X11Fns {
|
||||
void *lib = nullptr;
|
||||
void *display = nullptr;
|
||||
using XOpenDisplay = void *(*)(const char *);
|
||||
using XCloseDisplay = int (*)(void *);
|
||||
using XDefaultScreen = int (*)(void *);
|
||||
using XDefaultRootWindow = unsigned long (*)(void *);
|
||||
using XBlackPixel = unsigned long (*)(void *, int);
|
||||
using XCreateSimpleWindow = unsigned long (*)(void *, unsigned long, int, int, unsigned int, unsigned int,
|
||||
unsigned int, unsigned long, unsigned long);
|
||||
using XDestroyWindow = int (*)(void *, unsigned long);
|
||||
using XMapWindow = int (*)(void *, unsigned long);
|
||||
using XFlush = int (*)(void *);
|
||||
XOpenDisplay openDisplay = nullptr;
|
||||
XCloseDisplay closeDisplay = nullptr;
|
||||
XDefaultScreen defaultScreen = nullptr;
|
||||
XDefaultRootWindow defaultRootWindow = nullptr;
|
||||
XBlackPixel blackPixel = nullptr;
|
||||
XCreateSimpleWindow createSimpleWindow = nullptr;
|
||||
XDestroyWindow destroyWindow = nullptr;
|
||||
XMapWindow mapWindow = nullptr;
|
||||
XFlush flush = nullptr;
|
||||
};
|
||||
|
||||
EglFns gEgl;
|
||||
X11Fns gX11;
|
||||
EGLDisplay gDisplay = EGL_NO_DISPLAY;
|
||||
void *gMobileGl = nullptr;
|
||||
const glws::Drawable *gCurrentDrawable = nullptr;
|
||||
EGLContext gCurrentContext = EGL_NO_CONTEXT;
|
||||
int gRequestedWidth = 0;
|
||||
int gRequestedHeight = 0;
|
||||
bool gPrintedGlIdentity = false;
|
||||
|
||||
int ResolveWidth(int width) {
|
||||
if (gRequestedWidth > 0) {
|
||||
@@ -106,6 +135,7 @@ bool LoadEgl() {
|
||||
Load(gEgl.chooseConfig, "eglChooseConfig") &&
|
||||
Load(gEgl.createContext, "eglCreateContext") &&
|
||||
Load(gEgl.createPbufferSurface, "eglCreatePbufferSurface") &&
|
||||
Load(gEgl.createWindowSurface, "eglCreateWindowSurface") &&
|
||||
Load(gEgl.destroyContext, "eglDestroyContext") &&
|
||||
Load(gEgl.destroySurface, "eglDestroySurface") &&
|
||||
Load(gEgl.getConfigAttrib, "eglGetConfigAttrib") &&
|
||||
@@ -118,6 +148,108 @@ bool LoadEgl() {
|
||||
Load(gEgl.terminate, "eglTerminate");
|
||||
}
|
||||
|
||||
bool IsDirectVulkanBackend() {
|
||||
const char *backend = std::getenv("MOBILEGL_BACKEND_TYPE");
|
||||
return backend != nullptr && std::strcmp(backend, "DirectVulkan") == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool LoadX11(T &slot, const char *name) {
|
||||
slot = reinterpret_cast<T>(dlsym(gX11.lib, name));
|
||||
if (slot == nullptr) {
|
||||
std::cerr << "error: failed to resolve " << name << " from X11\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EnsureX11() {
|
||||
if (gX11.display != nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (gX11.lib == nullptr) {
|
||||
gX11.lib = dlopen("libX11.so.6", RTLD_LOCAL | RTLD_NOW);
|
||||
if (gX11.lib == nullptr) {
|
||||
gX11.lib = dlopen("libX11.so", RTLD_LOCAL | RTLD_NOW);
|
||||
}
|
||||
if (gX11.lib == nullptr) {
|
||||
std::cerr << "error: failed to open libX11 for DirectVulkan trace replay\n";
|
||||
return false;
|
||||
}
|
||||
if (!LoadX11(gX11.openDisplay, "XOpenDisplay") ||
|
||||
!LoadX11(gX11.closeDisplay, "XCloseDisplay") ||
|
||||
!LoadX11(gX11.defaultScreen, "XDefaultScreen") ||
|
||||
!LoadX11(gX11.defaultRootWindow, "XDefaultRootWindow") ||
|
||||
!LoadX11(gX11.blackPixel, "XBlackPixel") ||
|
||||
!LoadX11(gX11.createSimpleWindow, "XCreateSimpleWindow") ||
|
||||
!LoadX11(gX11.destroyWindow, "XDestroyWindow") ||
|
||||
!LoadX11(gX11.mapWindow, "XMapWindow") ||
|
||||
!LoadX11(gX11.flush, "XFlush")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
gX11.display = gX11.openDisplay(std::getenv("DISPLAY"));
|
||||
if (gX11.display == nullptr) {
|
||||
std::cerr << "error: XOpenDisplay failed for DirectVulkan trace replay\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long CreateX11Window(int width, int height) {
|
||||
if (!EnsureX11()) {
|
||||
return 0;
|
||||
}
|
||||
const int screen = gX11.defaultScreen(gX11.display);
|
||||
const unsigned long root = gX11.defaultRootWindow(gX11.display);
|
||||
const unsigned long black = gX11.blackPixel(gX11.display, screen);
|
||||
const unsigned long window = gX11.createSimpleWindow(gX11.display, root, 0, 0,
|
||||
static_cast<unsigned int>(std::max(width, 1)),
|
||||
static_cast<unsigned int>(std::max(height, 1)),
|
||||
0, black, black);
|
||||
if (window != 0) {
|
||||
gX11.mapWindow(gX11.display, window);
|
||||
gX11.flush(gX11.display);
|
||||
}
|
||||
return window;
|
||||
}
|
||||
|
||||
void DestroyX11Window(unsigned long window) {
|
||||
if (window != 0 && gX11.display != nullptr && gX11.destroyWindow != nullptr) {
|
||||
gX11.destroyWindow(gX11.display, window);
|
||||
gX11.flush(gX11.display);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintGlIdentityOnce() {
|
||||
if (gPrintedGlIdentity) {
|
||||
return;
|
||||
}
|
||||
auto glGetString = reinterpret_cast<PfnGlGetString>(Lookup("glGetString"));
|
||||
if (glGetString == nullptr) {
|
||||
std::cerr << "MOBILEGL_TRACE_GL_INFO unavailable: glGetString was not resolved\n";
|
||||
gPrintedGlIdentity = true;
|
||||
return;
|
||||
}
|
||||
constexpr unsigned int GL_VENDOR_ENUM = 0x1F00;
|
||||
constexpr unsigned int GL_RENDERER_ENUM = 0x1F01;
|
||||
constexpr unsigned int GL_VERSION_ENUM = 0x1F02;
|
||||
constexpr unsigned int GL_SHADING_LANGUAGE_VERSION_ENUM = 0x8B8C;
|
||||
auto stringOrUnknown = [glGetString](unsigned int name) {
|
||||
const auto *value = glGetString(name);
|
||||
return value == nullptr ? reinterpret_cast<const unsigned char *>("<null>") : value;
|
||||
};
|
||||
std::cerr << "MOBILEGL_TRACE_GL_VENDOR: "
|
||||
<< reinterpret_cast<const char *>(stringOrUnknown(GL_VENDOR_ENUM)) << "\n"
|
||||
<< "MOBILEGL_TRACE_GL_RENDERER: "
|
||||
<< reinterpret_cast<const char *>(stringOrUnknown(GL_RENDERER_ENUM)) << "\n"
|
||||
<< "MOBILEGL_TRACE_GL_VERSION: "
|
||||
<< reinterpret_cast<const char *>(stringOrUnknown(GL_VERSION_ENUM)) << "\n"
|
||||
<< "MOBILEGL_TRACE_GL_SHADING_LANGUAGE_VERSION: "
|
||||
<< reinterpret_cast<const char *>(stringOrUnknown(GL_SHADING_LANGUAGE_VERSION_ENUM)) << "\n";
|
||||
gPrintedGlIdentity = true;
|
||||
}
|
||||
|
||||
class EglVisual final : public glws::Visual {
|
||||
public:
|
||||
EGLConfig config = nullptr;
|
||||
@@ -129,6 +261,7 @@ public:
|
||||
class EglDrawable final : public glws::Drawable {
|
||||
public:
|
||||
EGLSurface surface = EGL_NO_SURFACE;
|
||||
unsigned long x11Window = 0;
|
||||
|
||||
EglDrawable(const EglVisual *visual, int width, int height, bool pbuffer)
|
||||
: Drawable(visual, width, height, pbuffer) {
|
||||
@@ -176,14 +309,26 @@ public:
|
||||
|
||||
private:
|
||||
void createSurface() {
|
||||
const EGLint attribs[] = {
|
||||
EGL_WIDTH, ResolveWidth(width),
|
||||
EGL_HEIGHT, ResolveHeight(height),
|
||||
EGL_NONE,
|
||||
};
|
||||
surface = gEgl.createPbufferSurface(gDisplay, static_cast<const EglVisual *>(visual)->config, attribs);
|
||||
const int resolvedWidth = ResolveWidth(width);
|
||||
const int resolvedHeight = ResolveHeight(height);
|
||||
if (IsDirectVulkanBackend()) {
|
||||
x11Window = CreateX11Window(resolvedWidth, resolvedHeight);
|
||||
if (x11Window == 0) {
|
||||
surface = EGL_NO_SURFACE;
|
||||
return;
|
||||
}
|
||||
surface = gEgl.createWindowSurface(gDisplay, static_cast<const EglVisual *>(visual)->config,
|
||||
reinterpret_cast<EGLNativeWindowType>(x11Window), nullptr);
|
||||
} else {
|
||||
const EGLint attribs[] = {
|
||||
EGL_WIDTH, resolvedWidth,
|
||||
EGL_HEIGHT, resolvedHeight,
|
||||
EGL_NONE,
|
||||
};
|
||||
surface = gEgl.createPbufferSurface(gDisplay, static_cast<const EglVisual *>(visual)->config, attribs);
|
||||
}
|
||||
if (surface == EGL_NO_SURFACE) {
|
||||
std::cerr << "error: EGL pbuffer creation failed: 0x" << std::hex
|
||||
std::cerr << "error: EGL surface creation failed: 0x" << std::hex
|
||||
<< gEgl.getError() << std::dec << "\n";
|
||||
}
|
||||
}
|
||||
@@ -193,6 +338,8 @@ private:
|
||||
gEgl.destroySurface(gDisplay, surface);
|
||||
surface = EGL_NO_SURFACE;
|
||||
}
|
||||
DestroyX11Window(x11Window);
|
||||
x11Window = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -337,6 +484,7 @@ bool makeCurrentInternal(Drawable *drawable, Drawable *readable, Context *contex
|
||||
}
|
||||
gCurrentDrawable = drawable;
|
||||
gCurrentContext = eglContext;
|
||||
PrintGlIdentityOnce();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user