milsko/src/widget/opengl.c
IoIxD 5315f4ec4d
Some checks failed
pyrite-dev/milsko/pipeline/head There was a failure building this commit
classic mac os
2026-04-15 20:21:20 -07:00

520 lines
15 KiB
C

#ifndef __APPLE__
#include <Mw/Milsko.h>
#include <Mw/Widget/OpenGL.h>
#ifdef USE_GDI
typedef HGLRC(WINAPI* MWwglCreateContext)(HDC);
typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC);
typedef PROC(WINAPI* MWwglGetProcAddress)(LPCSTR);
typedef BOOL(WINAPI* MWwglDeleteContext)(HGLRC);
typedef struct gdiopengl {
HDC dc;
HGLRC gl;
void* lib;
MWwglCreateContext wglCreateContext;
MWwglMakeCurrent wglMakeCurrent;
MWwglDeleteContext wglDeleteContext;
MWwglGetProcAddress wglGetProcAddress;
} gdiopengl_t;
#endif
#ifdef USE_X11
typedef XVisualInfo* (*MWglXChooseVisual)(Display* dpy, int screen,
int* attribList);
typedef GLXContext (*MWglXCreateContext)(Display* dpy, XVisualInfo* vis,
GLXContext shareList, Bool direct);
typedef void (*MWglXDestroyContext)(Display* dpy, GLXContext ctx);
typedef Bool (*MWglXMakeCurrent)(Display* dpy, GLXDrawable drawable,
GLXContext ctx);
typedef void (*MWglXSwapBuffers)(Display* dpy, GLXDrawable drawable);
typedef void* (*MWglXGetProcAddress)(const GLubyte* procname);
typedef struct x11opengl {
XVisualInfo* visual;
GLXContext gl;
void* lib;
MWglXChooseVisual glXChooseVisual;
MWglXCreateContext glXCreateContext;
MWglXDestroyContext glXDestroyContext;
MWglXMakeCurrent glXMakeCurrent;
MWglXSwapBuffers glXSwapBuffers;
MWglXGetProcAddress glXGetProcAddress;
} x11opengl_t;
#endif
#ifdef USE_WAYLAND
#include <EGL/egl.h>
#include <wayland-egl-core.h>
typedef struct waylandopengl {
EGLNativeWindowType egl_window_native;
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_surface;
EGLConfig egl_config;
void* gllib;
void* wlgllib;
EGLBoolean (*eglGetConfigs)(EGLDisplay display,
EGLConfig* configs,
EGLint config_size,
EGLint* num_config);
EGLBoolean (*eglInitialize)(EGLDisplay display,
EGLint* major,
EGLint* minor);
EGLContext (*eglCreateContext)(EGLDisplay display,
EGLConfig config,
EGLContext share_context,
EGLint const* attrib_list);
EGLBoolean (*eglMakeCurrent)(EGLDisplay display,
EGLSurface draw,
EGLSurface read,
EGLContext context);
void* (*eglGetProcAddress)(char const* procname);
EGLBoolean (*eglSwapBuffers)(EGLDisplay display,
EGLSurface surface);
EGLBoolean (*eglSwapInterval)(EGLDisplay display,
EGLint interval);
EGLint (*eglGetError)(void);
EGLBoolean (*eglBindAPI)(EGLenum api);
EGLDisplay (*eglGetDisplay)(NativeDisplayType native_display);
EGLSurface (*eglCreateWindowSurface)(EGLDisplay display,
EGLConfig config,
NativeWindowType native_window,
EGLint const* attrib_list);
EGLBoolean (*eglChooseConfig)(EGLDisplay display,
EGLint const* attrib_list,
EGLConfig* configs,
EGLint config_size,
EGLint* num_config);
struct wl_egl_window* (*wl_egl_window_create)(struct wl_surface* surface,
int width, int height);
void (*wl_egl_window_resize)(struct wl_egl_window* egl_window,
int width, int height,
int dx, int dy);
} waylandopengl_t;
#endif
static int wcreate(MwWidget handle) {
void* r = NULL;
MwWidget w = handle;
#ifdef USE_GDI
if(handle->lowlevel->common.type == MwLLBackendGDI) {
PIXELFORMATDESCRIPTOR pfd;
int pf;
gdiopengl_t* o = r = malloc(sizeof(*o));
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.cDepthBits = 32;
pfd.cColorBits = 32;
o->dc = GetDC(handle->lowlevel->gdi.hWnd);
pf = ChoosePixelFormat(o->dc, &pfd);
SetPixelFormat(o->dc, pf, &pfd);
o->lib = MwDynamicOpen("opengl32.dll");
o->wglCreateContext =
(MWwglCreateContext)(void*)MwDynamicSymbol(o->lib, "wglCreateContext");
o->wglMakeCurrent =
(MWwglMakeCurrent)(void*)MwDynamicSymbol(o->lib, "wglMakeCurrent");
o->wglDeleteContext =
(MWwglDeleteContext)(void*)MwDynamicSymbol(o->lib, "wglDeleteContext");
o->wglGetProcAddress = (MWwglGetProcAddress)(void*)MwDynamicSymbol(
o->lib, "wglGetProcAddress");
o->gl = o->wglCreateContext(o->dc);
}
#endif
#ifdef USE_X11
if(handle->lowlevel->common.type == MwLLBackendX11) {
int attribs[5];
const char* glpath[] = {"libGL.so", "/usr/local/lib/libGL.so",
"/usr/X11R7/lib/libGL.so", "/usr/pkg/lib/libGL.so"};
int glincr = 0;
x11opengl_t* o = r = malloc(sizeof(*o));
attribs[0] = GLX_RGBA;
attribs[1] = GLX_DOUBLEBUFFER;
attribs[2] = GLX_DEPTH_SIZE;
attribs[3] = 24;
attribs[4] = None;
while(glpath[glincr] != NULL &&
(o->lib = MwDynamicOpen(glpath[glincr++])) == NULL);
o->glXChooseVisual =
(MWglXChooseVisual)MwDynamicSymbol(o->lib, "glXChooseVisual");
o->glXCreateContext =
(MWglXCreateContext)MwDynamicSymbol(o->lib, "glXCreateContext");
o->glXDestroyContext =
(MWglXDestroyContext)MwDynamicSymbol(o->lib, "glXDestroyContext");
o->glXMakeCurrent =
(MWglXMakeCurrent)MwDynamicSymbol(o->lib, "glXMakeCurrent");
o->glXSwapBuffers =
(MWglXSwapBuffers)MwDynamicSymbol(o->lib, "glXSwapBuffers");
o->glXGetProcAddress =
(MWglXGetProcAddress)MwDynamicSymbol(o->lib, "glXGetProcAddress");
/* XXX: fix this */
o->visual = o->glXChooseVisual(handle->lowlevel->x11.display,
DefaultScreen(handle->lowlevel->x11.display),
attribs);
o->gl = o->glXCreateContext(handle->lowlevel->x11.display, o->visual, NULL,
GL_TRUE);
}
#endif
#ifdef USE_WAYLAND
if(handle->lowlevel->common.type == MwLLBackendWayland) {
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLContext context;
EGLSurface surface;
EGLint fbAttribs[] = {EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_DEPTH_SIZE,
24,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_BIT,
EGL_NONE};
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION,
1,
EGL_CONTEXT_MAJOR_VERSION,
1,
EGL_CONTEXT_MINOR_VERSION,
1,
EGL_NONE};
EGLDisplay display;
waylandopengl_t* o = r = malloc(sizeof(*o));
MwWaylandAlwaysRender = MwTRUE;
o->gllib = MwDynamicOpen("libEGL.so");
if(!o->gllib) {
printf("Could not load OpenGL widget under Wayland! libEGL.so missing.\n");
return 1;
}
o->wlgllib = MwDynamicOpen("libwayland-egl.so");
if(!o->gllib) {
printf("Could not load OpenGL widget under Wayland! libwayland-egl.so missing.\n");
return 1;
}
#define EGL_FUNC(x) \
o->x = MwDynamicSymbol(o->gllib, #x); \
if(!o->x) { \
printf("Could not load OpenGL widget under Wayland! " #x " missing.\n"); \
return 1; \
};
#define WAYLAND_EGL_FUNC(x) \
o->x = MwDynamicSymbol(o->wlgllib, #x); \
if(!o->x) { \
printf("Could not load OpenGL widget under Wayland! " #x " missing.\n"); \
return 1; \
};
EGL_FUNC(eglGetConfigs)
EGL_FUNC(eglInitialize)
EGL_FUNC(eglCreateContext)
EGL_FUNC(eglMakeCurrent)
EGL_FUNC(eglGetProcAddress)
EGL_FUNC(eglSwapBuffers)
EGL_FUNC(eglSwapInterval)
EGL_FUNC(eglGetError)
EGL_FUNC(eglBindAPI)
EGL_FUNC(eglGetDisplay)
EGL_FUNC(eglCreateWindowSurface)
EGL_FUNC(eglChooseConfig)
WAYLAND_EGL_FUNC(wl_egl_window_create)
WAYLAND_EGL_FUNC(wl_egl_window_resize)
#define eglGetConfigs o->eglGetConfigs
#define eglInitialize o->eglInitialize
#define eglCreateContext o->eglCreateContext
#define eglMakeCurrent o->eglMakeCurrent
#define eglGetProcAddress o->eglGetProcAddress
#define eglSwapBuffers o->eglSwapBuffers
#define eglSwapInterval o->eglSwapInterval
#define eglGetError o->eglGetError
#define wl_egl_window_create o->wl_egl_window_create
#define eglBindAPI o->eglBindAPI
#define eglGetDisplay o->eglGetDisplay
#define wl_egl_window_resize o->wl_egl_window_resize
#define eglCreateWindowSurface o->eglCreateWindowSurface
#define eglChooseConfig o->eglChooseConfig
display =
eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->wayland.display);
if(display == EGL_NO_DISPLAY) {
printf("ERROR: eglGetDisplay, %0X\n", eglGetError());
return MwFALSE;
}
/* Initialize EGL */
if(!eglInitialize(display, &majorVersion, &minorVersion)) {
printf("ERROR: eglInitialize, %0X\n", eglGetError());
return MwFALSE;
}
/* Get configs */
if((eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE) ||
(numConfigs == 0)) {
printf("ERROR: eglGetConfigs, %0X\n", eglGetError());
return MwFALSE;
}
/* Choose config */
if((eglChooseConfig(display, fbAttribs, &o->egl_config, 1, &numConfigs) !=
EGL_TRUE) ||
(numConfigs != 1)) {
printf("ERROR: eglChooseConfig, %0X\n", eglGetError());
return MwFALSE;
}
o->egl_window_native = (EGLNativeWindowType)wl_egl_window_create(
handle->lowlevel->wayland.framebuffer.surface,
handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh);
if(!o->egl_window_native) {
printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n");
return MwFALSE;
}
/* Create a surface */
surface = eglCreateWindowSurface(display, o->egl_config,
o->egl_window_native, NULL);
if(surface == EGL_NO_SURFACE) {
printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError());
return MwFALSE;
}
eglBindAPI(EGL_OPENGL_API);
/* Create a GL context */
context = eglCreateContext(display, o->egl_config, EGL_NO_CONTEXT,
contextAttribs);
if(context == EGL_NO_CONTEXT) {
printf("ERROR: eglCreateContext, %0X\n", eglGetError());
return MwFALSE;
}
if(!eglMakeCurrent(display, surface, surface, context)) {
printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError());
}
eglSwapInterval(o->egl_display, 0);
o->egl_display = display;
o->egl_surface = surface;
o->egl_context = context;
}
#endif
handle->internal = r;
handle->lowlevel->common.copy_buffer = 0;
MwSetDefault(handle);
while(w->parent != NULL)
w = w->parent;
w->berserk++;
return 0;
}
static void destroy(MwWidget handle) {
MwWidget w = handle;
#ifdef USE_GDI
if(handle->lowlevel->common.type == MwLLBackendGDI) {
gdiopengl_t* o = handle->internal;
o->wglMakeCurrent(NULL, NULL);
DeleteDC(o->dc);
o->wglDeleteContext(o->gl);
MwDynamicClose(o->lib);
}
#endif
#ifdef USE_X11
if(handle->lowlevel->common.type == MwLLBackendX11) {
x11opengl_t* o = handle->internal;
o->glXMakeCurrent(handle->lowlevel->x11.display, None, NULL);
o->glXDestroyContext(handle->lowlevel->x11.display, o->gl);
MwDynamicClose(o->lib);
}
#endif
#ifdef USE_WAYLAND
if(handle->lowlevel->common.type == MwLLBackendWayland) {
/* todo */
}
#endif
while(w->parent != NULL)
w = w->parent;
w->berserk--;
free(handle->internal);
}
static void mwOpenGLMakeCurrentImpl(MwWidget handle) {
/* these swap interval functions belonging here actually stink! */
#ifdef USE_GDI
if(handle->lowlevel->common.type == MwLLBackendGDI) {
gdiopengl_t* o = handle->internal;
void (*swap_interval_ext)(int) = NULL;
o->wglMakeCurrent(o->dc, o->gl);
if((swap_interval_ext =
MwOpenGLGetProcAddress(handle, "wglSwapIntervalEXT")) != NULL) {
swap_interval_ext(1);
}
}
#endif
#ifdef USE_X11
if(handle->lowlevel->common.type == MwLLBackendX11) {
x11opengl_t* o = handle->internal;
void (*swap_interval_ext)(Display*, GLXDrawable, int) = NULL;
void (*swap_interval_mesa)(unsigned int) = NULL;
void (*swap_interval_sgi)(int) = NULL;
o->glXMakeCurrent(handle->lowlevel->x11.display,
handle->lowlevel->x11.window, o->gl);
if((swap_interval_ext =
MwOpenGLGetProcAddress(handle, "glXSwapIntervalEXT")) != NULL) {
swap_interval_ext(handle->lowlevel->x11.display,
handle->lowlevel->x11.window, 1);
}
if((swap_interval_mesa =
MwOpenGLGetProcAddress(handle, "glXSwapIntervalMESA")) != NULL) {
swap_interval_mesa(1);
}
if((swap_interval_sgi =
MwOpenGLGetProcAddress(handle, "glXSwapIntervalSGI")) != NULL) {
swap_interval_sgi(1);
}
}
#endif
#ifdef USE_WAYLAND
if(handle->lowlevel->common.type == MwLLBackendWayland) {
waylandopengl_t* o = handle->internal;
if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface,
o->egl_context)) {
printf("ERROR: eglMakeCurrent, %0X\n", eglGetError());
}
}
#endif
}
static void mwOpenGLSwapBufferImpl(MwWidget handle) {
#ifdef USE_GDI
if(handle->lowlevel->common.type == MwLLBackendGDI) {
gdiopengl_t* o = handle->internal;
SwapBuffers(o->dc);
}
#endif
#ifdef USE_X11
if(handle->lowlevel->common.type == MwLLBackendX11) {
x11opengl_t* o = handle->internal;
o->glXSwapBuffers(handle->lowlevel->x11.display,
handle->lowlevel->x11.window);
}
#endif
#ifdef USE_WAYLAND
if(handle->lowlevel->common.type == MwLLBackendWayland) {
waylandopengl_t* o = handle->internal;
eglSwapInterval(o->egl_display, 0);
if(!eglSwapBuffers(o->egl_display, o->egl_surface)) {
printf("ERROR: eglSwapBuffers, %0X\n", eglGetError());
};
wl_egl_window_resize((struct wl_egl_window*)o->egl_window_native,
handle->lowlevel->wayland.ww,
handle->lowlevel->wayland.wh, 0, 0);
}
#endif
}
static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) {
#ifdef USE_GDI
if(handle->lowlevel->common.type == MwLLBackendGDI) {
gdiopengl_t* o = handle->internal;
return o->wglGetProcAddress(name);
}
#endif
#ifdef USE_X11
if(handle->lowlevel->common.type == MwLLBackendX11) {
x11opengl_t* o = handle->internal;
return o->glXGetProcAddress((const GLubyte*)name);
}
#endif
#ifdef USE_WAYLAND
if(handle->lowlevel->common.type == MwLLBackendWayland) {
waylandopengl_t* o = handle->internal;
return eglGetProcAddress(name);
}
#endif
return NULL;
}
static void func_handler(MwWidget handle, const char* name, void* out,
va_list va) {
if(strcmp(name, "mwOpenGLMakeCurrent") == 0) {
mwOpenGLMakeCurrentImpl(handle);
}
if(strcmp(name, "mwOpenGLSwapBuffer") == 0) {
mwOpenGLSwapBufferImpl(handle);
}
if(strcmp(name, "mwOpenGLGetProcAddress") == 0) {
const char* _name = va_arg(va, const char*);
*(void**)out = mwOpenGLGetProcAddressImpl(handle, _name);
}
}
MwClassRec MwOpenGLClassRec = {create, /* create */
destroy, /* destroy */
NULL, /* draw */
NULL, /* click */
NULL, /* parent_resize */
NULL, /* prop_change */
NULL, /* mouse_move */
NULL, /* mouse_up */
NULL, /* mouse_down */
NULL, /* key */
func_handler, /* execute */
NULL, /* tick */
NULL, /* resize */
NULL, /* children_update */
NULL, /* children_prop_change */
NULL, /* clipboard */
NULL, NULL, NULL, NULL};
MwClass MwOpenGLClass = &MwOpenGLClassRec;
#endif