aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-10-10 13:56:10 +0200
committerdec05eba <dec05eba@protonmail.com>2021-10-10 13:59:44 +0200
commit54b2376adad98d91d32378efc3f241f120ba970f (patch)
tree4556581f7c51f88e9cb1e5610bc8afef524340e1
parent3b2fceed064c06d55e1cd33d51e855e909c81f75 (diff)
Draw every frame instead of x11 expose, enable vsync (if available)
-rw-r--r--README.md5
-rw-r--r--include/mgl/gl.h17
-rw-r--r--include/mgl/glx.h21
-rw-r--r--include/mgl/mgl.h2
-rw-r--r--include/mgl/window.h3
-rw-r--r--src/gl.c34
-rw-r--r--src/glx.c55
-rw-r--r--src/mgl.c13
-rw-r--r--src/window.c63
-rw-r--r--tests/main.c3
10 files changed, 95 insertions, 121 deletions
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 <dlfcn.h>
-/*#include <GL/gl.h>*/
+/*#include <GL/glx.h>*/
#include <stdio.h>
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 <dlfcn.h>
-/*#include <GL/glx.h>*/
-#include <stdio.h>
-
-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);