From 54b2376adad98d91d32378efc3f241f120ba970f Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 10 Oct 2021 13:56:10 +0200 Subject: Draw every frame instead of x11 expose, enable vsync (if available) --- README.md | 5 +---- include/mgl/gl.h | 17 ++++++++++++++ include/mgl/glx.h | 21 ------------------ include/mgl/mgl.h | 2 -- include/mgl/window.h | 3 ++- src/gl.c | 34 +++++++++++++++++++++------- src/glx.c | 55 --------------------------------------------- src/mgl.c | 13 ++++------- src/window.c | 63 +++++++++++++++++++++++++++++++++++----------------- tests/main.c | 3 ++- 10 files changed, 95 insertions(+), 121 deletions(-) delete mode 100644 include/mgl/glx.h delete mode 100644 src/glx.c diff --git a/README.md b/README.md index 80de338..97cddfe 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,4 @@ Written in C. ## Build `xlib` ## Runtime -`libglvnd (libGLX.so, libOpenGL.so)` - -# TODO -vsync \ No newline at end of file +`libglvnd (libGL.so)` \ No newline at end of file diff --git a/include/mgl/gl.h b/include/mgl/gl.h index 1791059..b5b6ca1 100644 --- a/include/mgl/gl.h +++ b/include/mgl/gl.h @@ -1,11 +1,28 @@ #ifndef MGL_GL_H #define MGL_GL_H +typedef struct _XVisualInfo _XVisualInfo; +typedef struct _XDisplay Display; +typedef struct __GLXcontextRec *GLXContext; +typedef unsigned long GLXDrawable; + typedef struct { void *handle; + + _XVisualInfo* (*glXChooseVisual)(Display *dpy, int screen, int *attribList); + GLXContext (*glXCreateContext)(Display *dpy, _XVisualInfo *vis, GLXContext shareList, int direct); + void (*glXDestroyContext)(Display *dpy, GLXContext ctx); + int (*glXMakeCurrent)(Display *dpy, GLXDrawable drawable, GLXContext ctx); + void (*glXSwapBuffers)(Display *dpy, GLXDrawable drawable); + void (*glViewport)(int x, int y, int width, int height); void (*glClearColor)(float red, float green, float blue, float alpha); void (*glClear)(unsigned int mask); + + /* Optional*/ + void (*glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval); + int (*glXSwapIntervalMESA)(unsigned int interval); + int (*glXSwapIntervalSGI)(int interval); } mgl_gl; int mgl_gl_load(mgl_gl *self); diff --git a/include/mgl/glx.h b/include/mgl/glx.h deleted file mode 100644 index 4197402..0000000 --- a/include/mgl/glx.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef MGL_GLX_H -#define MGL_GLX_H - -typedef struct _XVisualInfo _XVisualInfo; -typedef struct _XDisplay Display; -typedef struct __GLXcontextRec *GLXContext; -typedef unsigned long GLXDrawable; - -typedef struct { - void *handle; - _XVisualInfo* (*glXChooseVisual)(Display *dpy, int screen, int *attribList); - GLXContext (*glXCreateContext)(Display *dpy, _XVisualInfo *vis, GLXContext shareList, int direct); - void (*glXDestroyContext)(Display *dpy, GLXContext ctx); - int (*glXMakeCurrent)(Display *dpy, GLXDrawable drawable, GLXContext ctx); - void (*glXSwapBuffers)(Display *dpy, GLXDrawable drawable); -} mgl_glx; - -int mgl_glx_load(mgl_glx *self); -void mgl_glx_unload(mgl_glx *self); - -#endif /* MGL_GLX_H */ diff --git a/include/mgl/mgl.h b/include/mgl/mgl.h index 606c14b..e906bc1 100644 --- a/include/mgl/mgl.h +++ b/include/mgl/mgl.h @@ -1,7 +1,6 @@ #ifndef MGL_MGL_H #define MGL_MGL_H -#include "glx.h" #include "gl.h" /* Display* on x11 */ @@ -11,7 +10,6 @@ typedef struct { mgl_connection connection; GLXContext glx_context; _XVisualInfo *visual_info; - mgl_glx glx; mgl_gl gl; } mgl_context; diff --git a/include/mgl/window.h b/include/mgl/window.h index c6dc9e2..57e3072 100644 --- a/include/mgl/window.h +++ b/include/mgl/window.h @@ -18,6 +18,7 @@ int mgl_window_create_with_params(mgl_window *self, const char *title, int width void mgl_window_deinit(mgl_window *self); void mgl_window_show(mgl_window *self); -void mgl_window_event_poll(mgl_window *self, int timeout_ms); +void mgl_window_event_poll(mgl_window *self); +void mgl_window_draw(mgl_window *self); #endif /* MGL_WINDOW_H */ diff --git a/src/gl.c b/src/gl.c index c83ab49..023ffbb 100644 --- a/src/gl.c +++ b/src/gl.c @@ -1,6 +1,6 @@ #include "../include/mgl/gl.h" #include -/*#include */ +/*#include */ #include typedef struct { @@ -20,28 +20,46 @@ static void* dlsym_print_fail(void *handle, const char *name) { } int mgl_gl_load(mgl_gl *self) { - const char *gl_path = "/usr/lib/libOpenGL.so.0"; - self->handle = dlopen(gl_path, RTLD_LAZY); + const char *glx_path = "/usr/lib/libGL.so.1"; + self->handle = dlopen(glx_path, RTLD_LAZY); if(!self->handle) { - fprintf(stderr, "dlopen(\"%s\", RTLD_LAZY) failed\n", gl_path); + fprintf(stderr, "dlopen(\"%s\", RTLD_LAZY) failed\n", glx_path); return -1; } - const dlsym_assign assign[] = { + const dlsym_assign required_dlsym[] = { + { &self->glXChooseVisual, "glXChooseVisual" }, + { &self->glXCreateContext, "glXCreateContext" }, + { &self->glXDestroyContext, "glXDestroyContext" }, + { &self->glXMakeCurrent, "glXMakeCurrent" }, + { &self->glXSwapBuffers, "glXSwapBuffers" }, + { &self->glViewport, "glViewport" }, { &self->glClearColor, "glClearColor" }, { &self->glClear, "glClear" }, + { NULL, NULL } }; - for(int i = 0; assign[i].func; ++i) { - *assign[i].func = dlsym_print_fail(self->handle, assign[i].name); - if(!assign[i].func) { + for(int i = 0; required_dlsym[i].func; ++i) { + *required_dlsym[i].func = dlsym_print_fail(self->handle, required_dlsym[i].name); + if(!required_dlsym[i].func) { mgl_gl_unload(self); return -1; } } + const dlsym_assign optional_dlsym[] = { + { &self->glXSwapIntervalEXT, "glXSwapIntervalEXT" }, + { &self->glXSwapIntervalMESA, "glXGetSwapIntervalMESA" }, + { &self->glXSwapIntervalSGI, "glXSwapIntervalSGI" }, + { NULL, NULL } + }; + + for(int i = 0; optional_dlsym[i].func; ++i) { + *optional_dlsym[i].func = dlsym_print_fail(self->handle, optional_dlsym[i].name); + } + return 0; } diff --git a/src/glx.c b/src/glx.c deleted file mode 100644 index 6712947..0000000 --- a/src/glx.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "../include/mgl/glx.h" -#include -/*#include */ -#include - -typedef struct { - void **func; - const char *name; -} dlsym_assign; - -static void* dlsym_print_fail(void *handle, const char *name) { - dlerror(); - void *sym = dlsym(handle, name); - char *err_str = dlerror(); - - if(!sym) - fprintf(stderr, "dlsym(handle, \"%s\") failed, error: %s\n", name, err_str ? err_str : "(null)"); - - return sym; -} - -int mgl_glx_load(mgl_glx *self) { - const char *glx_path = "/usr/lib/libGLX.so.0"; - self->handle = dlopen(glx_path, RTLD_LAZY); - if(!self->handle) { - fprintf(stderr, "dlopen(\"%s\", RTLD_LAZY) failed\n", glx_path); - return -1; - } - - const dlsym_assign assign[] = { - { &self->glXChooseVisual, "glXChooseVisual" }, - { &self->glXCreateContext, "glXCreateContext" }, - { &self->glXDestroyContext, "glXDestroyContext" }, - { &self->glXMakeCurrent, "glXMakeCurrent" }, - { &self->glXSwapBuffers, "glXSwapBuffers" }, - { NULL, NULL } - }; - - for(int i = 0; assign[i].func; ++i) { - *assign[i].func = dlsym_print_fail(self->handle, assign[i].name); - if(!assign[i].func) { - mgl_glx_unload(self); - return -1; - } - } - - return 0; -} - -void mgl_glx_unload(mgl_glx *self) { - if(self->handle) { - dlclose(self->handle); - self->handle = NULL; - } -} diff --git a/src/mgl.c b/src/mgl.c index 27d33ae..02ed363 100644 --- a/src/mgl.c +++ b/src/mgl.c @@ -44,13 +44,13 @@ static int glx_context_init() { None }; - context.visual_info = context.glx.glXChooseVisual(context.connection, DefaultScreen(context.connection), (int*)attr); + context.visual_info = context.gl.glXChooseVisual(context.connection, DefaultScreen(context.connection), (int*)attr); if(!context.visual_info) { fprintf(stderr, "glXChooseVisual failed, no appropriate visual found\n"); return -1; } - context.glx_context = context.glx.glXCreateContext(context.connection, context.visual_info, NULL, 1); + context.glx_context = context.gl.glXCreateContext(context.connection, context.visual_info, NULL, 1); if(!context.glx_context) { fprintf(stderr, "glXCreateContext failed\n"); return -1; @@ -61,7 +61,7 @@ static int glx_context_init() { static void glx_context_deinit() { if(context.glx_context) { - context.glx.glXDestroyContext(context.connection, context.glx_context); + context.gl.glXDestroyContext(context.connection, context.glx_context); context.glx_context = NULL; } @@ -83,11 +83,6 @@ int mgl_init(void) { prev_xerror = XSetErrorHandler(ignore_xerror); - if(mgl_glx_load(&context.glx) != 0) { - mgl_deinit(); - return -1; - } - if(mgl_gl_load(&context.gl) != 0) { mgl_deinit(); return -1; @@ -105,7 +100,7 @@ void mgl_deinit(void) { if(init_count == 1) { glx_context_deinit(); mgl_gl_unload(&context.gl); - mgl_glx_unload(&context.glx); + mgl_gl_unload(&context.gl); XSetErrorHandler(prev_xerror); if(context.connection) { XCloseDisplay(context.connection); diff --git a/src/window.c b/src/window.c index 9836907..bdbcd6f 100644 --- a/src/window.c +++ b/src/window.c @@ -24,7 +24,7 @@ int mgl_window_create_with_params(mgl_window *self, const char *title, int width XSetWindowAttributes window_attr; window_attr.colormap = color_map; - window_attr.event_mask = ExposureMask | KeyPressMask; + window_attr.event_mask = KeyPressMask; self->window = XCreateWindow(context->connection, parent_window, 0, 0, width, height, 0, ((XVisualInfo*)context->visual_info)->depth, InputOutput, ((XVisualInfo*)context->visual_info)->visual, CWColormap | CWEventMask, &window_attr); //XFreeColormap(context->connection, color_map); @@ -48,19 +48,27 @@ void mgl_window_deinit(mgl_window *self) { } } -static void mgl_window_draw(mgl_window *self) { +/* TODO: check for glx swap control extension string (GLX_EXT_swap_control, etc) */ +static void set_vertical_sync_enabled(Window window, int enabled) { + int result = 0; mgl_context *context = mgl_get_context(); - /* TODO: Get window size from window resize event instead */ - XWindowAttributes gwa; - XGetWindowAttributes(context->connection, self->window, &gwa); + if(context->gl.glXSwapIntervalEXT) { + context->gl.glXSwapIntervalEXT(context->connection, window, enabled ? 1 : 0); + } else if(context->gl.glXSwapIntervalMESA) { + result = context->gl.glXSwapIntervalMESA(enabled ? 1 : 0); + } else if(context->gl.glXSwapIntervalSGI) { + result = context->gl.glXSwapIntervalSGI(enabled ? 1 : 0); + } else { + static int warned = 0; + if (!warned) { + warned = 1; + fprintf(stderr, "Warning: setting vertical sync not supported\n"); + } + } - context->gl.glViewport(0, 0, gwa.width, gwa.height); - context->gl.glClear(GL_COLOR_BUFFER_BIT); - context->gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - if(self->callback.draw) - self->callback.draw(self, self->callback_userdata); - context->glx.glXSwapBuffers(context->connection, self->window); + if(result != 0) + fprintf(stderr, "Warning: setting vertical sync failed\n"); } void mgl_window_show(mgl_window *self) { @@ -70,19 +78,16 @@ void mgl_window_show(mgl_window *self) { XFlush(context->connection); /* TODO: Switch current when rendering to another window, and set current to NULL when destroying the currently selected context */ - context->glx.glXMakeCurrent(context->connection, self->window, context->glx_context); + context->gl.glXMakeCurrent(context->connection, self->window, context->glx_context); + set_vertical_sync_enabled(self->window, 1); mgl_window_draw(self); } static void on_receive_x11_event(mgl_window *window, XEvent *xev) { - switch(xev->type) { - case Expose: - mgl_window_draw(window); - break; - } + } -void mgl_window_event_poll(mgl_window *self, int timeout_ms) { +void mgl_window_event_poll(mgl_window *self) { Display *display = mgl_get_context()->connection; const int x11_fd = ConnectionNumber(display); @@ -91,9 +96,12 @@ void mgl_window_event_poll(mgl_window *self, int timeout_ms) { FD_SET(x11_fd, &in_fds); struct timeval tv; - tv.tv_sec = timeout_ms / 1000; - tv.tv_usec = (timeout_ms * 1000) - (tv.tv_sec * 1000 * 1000); + tv.tv_sec = 0; + tv.tv_usec = 0; + /*tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms * 1000) - (tv.tv_sec * 1000 * 1000);*/ + /* TODO: Is this needed when using XPending? */ const int num_ready_fds = select(1 + x11_fd, &in_fds, NULL, NULL, &tv); if(num_ready_fds > 0) { XEvent xev; @@ -103,3 +111,18 @@ void mgl_window_event_poll(mgl_window *self, int timeout_ms) { } } } + +void mgl_window_draw(mgl_window *self) { + mgl_context *context = mgl_get_context(); + + /* TODO: Get window size from window resize event instead */ + XWindowAttributes gwa; + XGetWindowAttributes(context->connection, self->window, &gwa); + + context->gl.glViewport(0, 0, gwa.width, gwa.height); + context->gl.glClear(GL_COLOR_BUFFER_BIT); + context->gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + if(self->callback.draw) + self->callback.draw(self, self->callback_userdata); + context->gl.glXSwapBuffers(context->connection, self->window); +} diff --git a/tests/main.c b/tests/main.c index e6a4f5a..dfea218 100644 --- a/tests/main.c +++ b/tests/main.c @@ -26,7 +26,8 @@ int main(int argc, char **argv) { mgl_window_show(&window); for(;;) { - mgl_window_event_poll(&window, 500); + mgl_window_event_poll(&window); + mgl_window_draw(&window); } mgl_window_deinit(&window); -- cgit v1.2.3