diff options
author | David Robillard <d@drobilla.net> | 2019-07-27 21:24:36 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2019-07-29 01:59:19 +0200 |
commit | 37fe29ab9c4a5ea22bc5996b020fa39c854965fa (patch) | |
tree | 5ac433830c4113d07c51b662ca6d4707d4be12e8 /pugl/detail/x11_gl.c | |
parent | 41dea932f866c10eb9c303298545d6b7151cfcd0 (diff) | |
download | pugl-37fe29ab9c4a5ea22bc5996b020fa39c854965fa.tar.gz pugl-37fe29ab9c4a5ea22bc5996b020fa39c854965fa.tar.bz2 pugl-37fe29ab9c4a5ea22bc5996b020fa39c854965fa.zip |
Reorganize source to separate private implementation details
Taking a page from C++ convention, where "detail" is for things that should not
be included in user code.
Diffstat (limited to 'pugl/detail/x11_gl.c')
-rw-r--r-- | pugl/detail/x11_gl.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/pugl/detail/x11_gl.c b/pugl/detail/x11_gl.c new file mode 100644 index 0000000..7fcf169 --- /dev/null +++ b/pugl/detail/x11_gl.c @@ -0,0 +1,213 @@ +/* + Copyright 2012-2019 David Robillard <http://drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** + @file x11_gl.c OpenGL graphics backend for X11. +*/ + +#include "pugl/detail/implementation.h" +#include "pugl/detail/x11.h" +#include "pugl/pugl_gl_backend.h" + +#include <GL/gl.h> +#include <GL/glx.h> + +#include <stdlib.h> +#include <stdio.h> + +typedef struct { + GLXFBConfig fb_config; + GLXContext ctx; + int double_buffered; +} PuglX11GlSurface; + +static int +puglX11GlHintValue(const int value) +{ + return value == PUGL_DONT_CARE ? (int)GLX_DONT_CARE : value; +} + +static int +puglX11GlGetAttrib(Display* const display, + const GLXFBConfig fb_config, + const int attrib) +{ + int value = 0; + glXGetFBConfigAttrib(display, fb_config, attrib, &value); + return value; +} + +static int +puglX11GlConfigure(PuglView* view) +{ + PuglInternals* const impl = view->impl; + const int screen = impl->screen; + Display* const display = impl->display; + + PuglX11GlSurface* const surface = + (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface)); + impl->surface = surface; + + const int attrs[] = { + GLX_X_RENDERABLE, True, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_SAMPLES, view->hints.samples, + GLX_RED_SIZE, puglX11GlHintValue(view->hints.red_bits), + GLX_GREEN_SIZE, puglX11GlHintValue(view->hints.green_bits), + GLX_BLUE_SIZE, puglX11GlHintValue(view->hints.blue_bits), + GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints.alpha_bits), + GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints.depth_bits), + GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints.stencil_bits), + GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints.double_buffer), + None + }; + + int n_fbc = 0; + GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc); + if (n_fbc <= 0) { + fprintf(stderr, "error: Failed to create GL context\n"); + return 1; + } + + surface->fb_config = fbc[0]; + impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]); + + printf("Using visual 0x%lX: R=%d G=%d B=%d A=%d D=%d" + " DOUBLE=%d SAMPLES=%d\n", + impl->vi->visualid, + puglX11GlGetAttrib(display, fbc[0], GLX_RED_SIZE), + puglX11GlGetAttrib(display, fbc[0], GLX_GREEN_SIZE), + puglX11GlGetAttrib(display, fbc[0], GLX_BLUE_SIZE), + puglX11GlGetAttrib(display, fbc[0], GLX_ALPHA_SIZE), + puglX11GlGetAttrib(display, fbc[0], GLX_DEPTH_SIZE), + puglX11GlGetAttrib(display, fbc[0], GLX_DOUBLEBUFFER), + puglX11GlGetAttrib(display, fbc[0], GLX_SAMPLES)); + + XFree(fbc); + + return 0; +} + +static int +puglX11GlCreate(PuglView* view) +{ + PuglInternals* const impl = view->impl; + PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface; + Display* const display = impl->display; + const GLXFBConfig fb_config = surface->fb_config; + + const int ctx_attrs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, view->hints.context_version_major, + GLX_CONTEXT_MINOR_VERSION_ARB, view->hints.context_version_minor, + GLX_CONTEXT_PROFILE_MASK_ARB, (view->hints.use_compat_profile + ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB + : GLX_CONTEXT_CORE_PROFILE_BIT_ARB), + 0}; + + typedef GLXContext (*CreateContextAttribs)( + Display*, GLXFBConfig, GLXContext, Bool, const int*); + + CreateContextAttribs create_context = + (CreateContextAttribs)glXGetProcAddress( + (const GLubyte*)"glXCreateContextAttribsARB"); + + impl->surface = surface; + surface->ctx = create_context(display, fb_config, 0, GL_TRUE, ctx_attrs); + if (!surface->ctx) { + surface->ctx = + glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True); + } + + glXGetConfig(impl->display, + impl->vi, + GLX_DOUBLEBUFFER, + &surface->double_buffered); + + return 0; +} + +static int +puglX11GlDestroy(PuglView* view) +{ + PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; + if (surface) { + glXDestroyContext(view->impl->display, surface->ctx); + free(surface); + view->impl->surface = NULL; + } + return 0; +} + +static int +puglX11GlEnter(PuglView* view, bool PUGL_UNUSED(drawing)) +{ + PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; + glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx); + return 0; +} + +static int +puglX11GlLeave(PuglView* view, bool drawing) +{ + PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; + + if (drawing && surface->double_buffered) { + glXSwapBuffers(view->impl->display, view->impl->win); + } else if (drawing) { + glFlush(); + } + + glXMakeCurrent(view->impl->display, None, NULL); + + return 0; +} + +static int +puglX11GlResize(PuglView* PUGL_UNUSED(view), + int PUGL_UNUSED(width), + int PUGL_UNUSED(height)) +{ + return 0; +} + +static void* +puglX11GlGetContext(PuglView* PUGL_UNUSED(view)) +{ + return NULL; +} + +PuglGlFunc +puglGetProcAddress(const char* name) +{ + return glXGetProcAddress((const GLubyte*)name); +} + +const PuglBackend* puglGlBackend(void) +{ + static const PuglBackend backend = { + puglX11GlConfigure, + puglX11GlCreate, + puglX11GlDestroy, + puglX11GlEnter, + puglX11GlLeave, + puglX11GlResize, + puglX11GlGetContext + }; + + return &backend; +} |