aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl/libui/unix/gl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libui_sdl/libui/unix/gl.c')
-rw-r--r--src/libui_sdl/libui/unix/gl.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/libui_sdl/libui/unix/gl.c b/src/libui_sdl/libui/unix/gl.c
new file mode 100644
index 0000000..e1665ee
--- /dev/null
+++ b/src/libui_sdl/libui/unix/gl.c
@@ -0,0 +1,246 @@
+// 26 may 2019
+#include "uipriv_unix.h"
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <EGL/egl.h>
+
+extern GThread* gtkthread;
+extern GMutex glmutex;
+
+struct uiGLContext
+{
+ GtkWidget* widget;
+ GdkWindow* window;
+
+ GdkGLContext *gctx;
+ int vermaj, vermin;
+
+ int width, height;
+ int scale;
+ GLuint renderbuffer[2][2];
+ GLuint framebuffer[2];
+ int backbuffer;
+};
+
+static void areaAllocRenderbuffer(uiGLContext* glctx);
+
+static PFNGLGENRENDERBUFFERSPROC _glGenRenderbuffers;
+static PFNGLDELETERENDERBUFFERSPROC _glDeleteRenderbuffers;
+static PFNGLBINDRENDERBUFFERPROC _glBindRenderbuffer;
+static PFNGLRENDERBUFFERSTORAGEPROC _glRenderbufferStorage;
+static PFNGLGETRENDERBUFFERPARAMETERIVPROC _glGetRenderbufferParameteriv;
+
+static PFNGLGENRENDERBUFFERSPROC _glGenFramebuffers;
+static PFNGLDELETERENDERBUFFERSPROC _glDeleteFramebuffers;
+static PFNGLBINDRENDERBUFFERPROC _glBindFramebuffer;
+static PFNGLFRAMEBUFFERTEXTUREPROC _glFramebufferTexture;
+static PFNGLFRAMEBUFFERRENDERBUFFERPROC _glFramebufferRenderbuffer;
+static PFNGLCHECKFRAMEBUFFERSTATUSPROC _glCheckFramebufferStatus;
+
+static int _procsLoaded = 0;
+
+static void _loadGLProcs(GdkGLContext* glctx)
+{
+ if (_procsLoaded) return;
+
+ _glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)uiGLGetProcAddress("glGenRenderbuffers");
+ _glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)uiGLGetProcAddress("glDeleteRenderbuffers");
+ _glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)uiGLGetProcAddress("glBindRenderbuffer");
+ _glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)uiGLGetProcAddress("glRenderbufferStorage");
+ _glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)uiGLGetProcAddress("glGetRenderbufferParameteriv");
+
+ _glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)uiGLGetProcAddress("glGenFramebuffers");
+ _glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)uiGLGetProcAddress("glDeleteFramebuffers");
+ _glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)uiGLGetProcAddress("glBindFramebuffer");
+ _glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)uiGLGetProcAddress("glFramebufferTexture");
+ _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)uiGLGetProcAddress("glFramebufferRenderbuffer");
+ _glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)uiGLGetProcAddress("glCheckFramebufferStatus");
+
+ _procsLoaded = 1;
+}
+
+uiGLContext *createGLContext(GtkWidget* widget, int maj, int min)
+{
+ GdkWindow* gdkwin = gtk_widget_get_window(widget);
+
+ GError* err = NULL;
+ GdkGLContext* gctx = gdk_window_create_gl_context(gdkwin, &err);
+ if (err != NULL || gctx == NULL)
+ {
+ return NULL;
+ }
+
+ // TODO: make the set_use_es call conditional (#ifdef or smth) for older versions of gdk?
+ gdk_gl_context_set_use_es(gctx, FALSE);
+ gdk_gl_context_set_required_version(gctx, maj, min);
+
+ gboolean res = gdk_gl_context_realize(gctx, &err);
+ if (err != NULL || res == FALSE)
+ {
+ return NULL;
+ }
+
+ uiGLContext* ctx = uiNew(uiGLContext);
+
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(widget, &allocation);
+ int window_scale = gdk_window_get_scale_factor(gdkwin);
+ ctx->width = allocation.width;
+ ctx->height = allocation.height;
+ ctx->scale = window_scale;
+
+ gdk_gl_context_make_current(gctx);
+ _loadGLProcs(gctx);
+ areaAllocRenderbuffer(ctx);
+ ctx->backbuffer = 0;
+
+ ctx->widget = widget;
+ ctx->window = gdkwin;
+ ctx->gctx = gctx;
+
+ return ctx;
+}
+
+void freeGLContext(uiGLContext* glctx)
+{
+ if (glctx == NULL) return;
+
+ gdk_gl_context_make_current(glctx->gctx);
+ _glDeleteRenderbuffers(4, &glctx->renderbuffer[0][0]);
+ _glDeleteFramebuffers(2, &glctx->framebuffer[0]);
+
+ gdk_gl_context_clear_current();
+ g_object_unref(glctx->gctx);
+ uiFree(glctx);
+}
+
+static void areaAllocRenderbuffer(uiGLContext* glctx)
+{
+ // TODO: create textures as a fallback if GL_RGB renderbuffer isn't supported?
+ // they say GL implementations aren't required to support a GL_RGB renderbuffer
+ // however, a GL_RGBA one would cause gdk_cairo_draw_from_gl() to fall back to glReadPixels()
+
+ _glGenRenderbuffers(4, &glctx->renderbuffer[0][0]);
+ _glGenFramebuffers(2, &glctx->framebuffer[0]);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[1]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+
+ //if (_glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ // printf("FRAMEBUFFER IS BAD!! %04X\n", _glCheckFramebufferStatus(GL_FRAMEBUFFER));
+}
+
+static void areaReallocRenderbuffer(uiGLContext* glctx)
+{
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+
+ _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
+ _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
+ //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
+}
+
+void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx)
+{
+ int window_scale = gdk_window_get_scale_factor(glctx->window);
+
+ if (glctx->width != dp->AreaWidth || glctx->height != dp->AreaHeight || glctx->scale != window_scale)
+ {
+ glctx->width = dp->AreaWidth;
+ glctx->height = dp->AreaHeight;
+ glctx->scale = window_scale;
+ areaReallocRenderbuffer(glctx);
+ }
+ else
+ {
+ gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(widget),
+ glctx->renderbuffer[glctx->backbuffer][0], GL_RENDERBUFFER,
+ 1, 0, 0, glctx->width*glctx->scale, glctx->height*glctx->scale);
+ }
+}
+
+int uiGLGetFramebuffer(uiGLContext* ctx)
+{
+ return ctx->framebuffer[ctx->backbuffer];
+}
+
+float uiGLGetFramebufferScale(uiGLContext* ctx)
+{
+ return (float)ctx->scale;
+}
+
+void uiGLSwapBuffers(uiGLContext* ctx)
+{
+ ctx->backbuffer = ctx->backbuffer ? 0 : 1;
+}
+
+void uiGLMakeContextCurrent(uiGLContext* ctx)
+{
+ if (!ctx)
+ {
+ gdk_gl_context_clear_current();
+ return;
+ }
+
+ if (ctx->gctx == gdk_gl_context_get_current()) return;
+ gdk_gl_context_make_current(ctx->gctx);
+}
+
+void uiGLBegin(uiGLContext* ctx)
+{
+ if (g_thread_self() != gtkthread)
+ {
+ g_mutex_lock(&glmutex);
+ }
+}
+
+void uiGLEnd(uiGLContext* ctx)
+{
+ if (g_thread_self() != gtkthread)
+ {
+ g_mutex_unlock(&glmutex);
+ }
+}
+
+void *uiGLGetProcAddress(const char* proc)
+{
+ // TODO: consider using epoxy or something funny
+
+ void* ptr;
+
+ ptr = glXGetProcAddressARB((const GLubyte*)proc);
+ if (ptr) return ptr;
+
+ ptr = eglGetProcAddress(proc);
+ if (ptr) return ptr;
+
+ ptr = dlsym(NULL /* RTLD_DEFAULT */, proc);
+ if (ptr) return ptr;
+
+ return NULL;
+}
+unsigned int uiGLGetVersion(uiGLContext* ctx)
+{
+ if (!ctx) return 0;
+ return uiGLVersion(ctx->vermaj, ctx->vermin);
+}
+