diff options
author | David Robillard <d@drobilla.net> | 2019-02-17 20:49:15 +0100 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2019-02-17 21:16:57 +0100 |
commit | 197c19b74bd26f5a7526a88621a556f551b2db5a (patch) | |
tree | c9462855439c6f9cbd9f02cd5d754e5b55a73835 | |
parent | 51dcb00d5a5e6874f1e83d9cafb9ca2c1bd8bbf7 (diff) |
Add configuration API
-rw-r--r-- | pugl/pugl.h | 33 | ||||
-rw-r--r-- | pugl/pugl_internal.h | 56 | ||||
-rw-r--r-- | pugl/pugl_internal_types.h | 39 | ||||
-rw-r--r-- | pugl/pugl_osx.m | 4 | ||||
-rw-r--r-- | pugl/pugl_win.cpp | 2 | ||||
-rw-r--r-- | pugl/pugl_x11.c | 6 | ||||
-rw-r--r-- | pugl/pugl_x11_gl.c | 143 |
7 files changed, 221 insertions, 62 deletions
diff --git a/pugl/pugl.h b/pugl/pugl.h index 05366be..e57eb71 100644 --- a/pugl/pugl.h +++ b/pugl/pugl.h @@ -86,6 +86,33 @@ typedef enum { } PuglContextType; /** + Window hint. +*/ +typedef enum { + PUGL_USE_COMPAT_PROFILE, /**< Use compatible (not core) OpenGL profile */ + PUGL_CONTEXT_VERSION_MAJOR, /**< OpenGL context major version */ + PUGL_CONTEXT_VERSION_MINOR, /**< OpenGL context minor version */ + PUGL_RED_BITS, /**< Number of bits for red channel */ + PUGL_GREEN_BITS, /**< Number of bits for green channel */ + PUGL_BLUE_BITS, /**< Number of bits for blue channel */ + PUGL_ALPHA_BITS, /**< Number of bits for alpha channel */ + PUGL_DEPTH_BITS, /**< Number of bits for depth buffer */ + PUGL_STENCIL_BITS, /**< Number of bits for stencil buffer */ + PUGL_SAMPLES, /**< Number of samples per pixel (AA) */ + PUGL_DOUBLE_BUFFER, /**< True if double buffering should be used */ + PUGL_RESIZABLE, /**< True if window should be resizable */ +} PuglWindowHint; + +/** + Special window hint value. +*/ +typedef enum { + PUGL_DONT_CARE = -1, /**< Use best available value */ + PUGL_FALSE = 0, /**< Explicitly false */ + PUGL_TRUE = 1 /**< Explicitly true */ +} PuglWindowHintValue; + +/** Convenience symbols for ASCII control characters. */ typedef enum { @@ -381,6 +408,12 @@ PUGL_API PuglView* puglInit(int* pargc, char** argv); /** + Set a hint before creating a window. +*/ +PUGL_API void +puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value); + +/** Set the window class name before creating a window. */ PUGL_API void diff --git a/pugl/pugl_internal.h b/pugl/pugl_internal.h index 2b09761..2b54de4 100644 --- a/pugl/pugl_internal.h +++ b/pugl/pugl_internal.h @@ -36,6 +36,15 @@ PuglInternals* puglInitInternals(void); +static PuglHints +puglDefaultHints() +{ + static const PuglHints hints = { + 2, 0, 4, 4, 4, 4, 24, 8, 0, true, true, false + }; + return hints; +} + PuglView* puglInit(int* pargc, char** argv) { @@ -44,6 +53,8 @@ puglInit(int* pargc, char** argv) return NULL; } + view->hints = puglDefaultHints(); + PuglInternals* impl = puglInitInternals(); if (!impl) { return NULL; @@ -58,6 +69,49 @@ puglInit(int* pargc, char** argv) } void +puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value) +{ + switch (hint) { + case PUGL_USE_COMPAT_PROFILE: + view->hints.use_compat_profile = value; + break; + case PUGL_CONTEXT_VERSION_MAJOR: + view->hints.context_version_major = value; + break; + case PUGL_CONTEXT_VERSION_MINOR: + view->hints.context_version_minor = value; + break; + case PUGL_RED_BITS: + view->hints.red_bits = value; + break; + case PUGL_GREEN_BITS: + view->hints.green_bits = value; + break; + case PUGL_BLUE_BITS: + view->hints.blue_bits = value; + break; + case PUGL_ALPHA_BITS: + view->hints.alpha_bits = value; + break; + case PUGL_DEPTH_BITS: + view->hints.depth_bits = value; + break; + case PUGL_STENCIL_BITS: + view->hints.stencil_bits = value; + break; + case PUGL_SAMPLES: + view->hints.samples = value; + break; + case PUGL_DOUBLE_BUFFER: + view->hints.double_buffer = value; + break; + case PUGL_RESIZABLE: + view->hints.resizable = value; + break; + } +} + +void puglInitWindowSize(PuglView* view, int width, int height) { view->width = width; @@ -103,7 +157,7 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent) void puglInitResizable(PuglView* view, bool resizable) { - view->resizable = resizable; + view->hints.resizable = resizable; } void diff --git a/pugl/pugl_internal_types.h b/pugl/pugl_internal_types.h index 63b81cd..bbc39c0 100644 --- a/pugl/pugl_internal_types.h +++ b/pugl/pugl_internal_types.h @@ -29,6 +29,21 @@ /** Platform-specific internals. */ typedef struct PuglInternalsImpl PuglInternals; +typedef struct { + int context_version_major; + int context_version_minor; + int red_bits; + int green_bits; + int blue_bits; + int alpha_bits; + int depth_bits; + int stencil_bits; + int samples; + bool use_compat_profile; + bool double_buffer; + bool resizable; +} PuglHints; + /** Cross-platform view definition. */ struct PuglViewImpl { PuglHandle handle; @@ -41,18 +56,18 @@ struct PuglViewImpl { PuglContextType ctx_type; uintptr_t transient_parent; - int width; - int height; - int min_width; - int min_height; - int min_aspect_x; - int min_aspect_y; - int max_aspect_x; - int max_aspect_y; - bool ignoreKeyRepeat; - bool redisplay; - bool resizable; - bool visible; + PuglHints hints; + int width; + int height; + int min_width; + int min_height; + int min_aspect_x; + int min_aspect_y; + int max_aspect_x; + int max_aspect_y; + bool ignoreKeyRepeat; + bool redisplay; + bool visible; }; /** Opaque surface used by draw context. */ diff --git a/pugl/pugl_osx.m b/pugl/pugl_osx.m index 712f5fc..8e40907 100644 --- a/pugl/pugl_osx.m +++ b/pugl/pugl_osx.m @@ -583,7 +583,7 @@ puglCreateWindow(PuglView* view, const char* title) puglConstraint(impl->glview, NSLayoutAttributeWidth, view->min_width)]; [impl->glview addConstraint: puglConstraint(impl->glview, NSLayoutAttributeHeight, view->min_height)]; - if (!view->resizable) { + if (!view->hints.resizable) { [impl->glview setAutoresizingMask:NSViewNotSizable]; } @@ -598,7 +598,7 @@ puglCreateWindow(PuglView* view, const char* title) encoding:NSUTF8StringEncoding]; NSRect frame = NSMakeRect(0, 0, view->min_width, view->min_height); unsigned style = NSClosableWindowMask | NSTitledWindowMask; - if (view->resizable) { + if (view->hints.resizable) { style |= NSResizableWindowMask; } diff --git a/pugl/pugl_win.cpp b/pugl/pugl_win.cpp index fd14593..2c092eb 100644 --- a/pugl/pugl_win.cpp +++ b/pugl/pugl_win.cpp @@ -138,7 +138,7 @@ puglCreateWindow(PuglView* view, const char* title) } int winFlags = WS_POPUPWINDOW | WS_CAPTION; - if (view->resizable) { + if (view->hints.resizable) { winFlags |= WS_SIZEBOX; if (view->min_width || view->min_height) { // Adjust the minimum window size to accomodate requested view size diff --git a/pugl/pugl_x11.c b/pugl/pugl_x11.c index 5218433..6315759 100644 --- a/pugl/pugl_x11.c +++ b/pugl/pugl_x11.c @@ -88,8 +88,8 @@ puglCreateWindow(PuglView* view, const char* title) return 1; } - impl->ctx.configure(view); - if (!impl->vi) { + if (impl->ctx.configure(view) || !impl->vi) { + impl->ctx.destroy(view); return 2; } @@ -120,7 +120,7 @@ puglCreateWindow(PuglView* view, const char* title) XSizeHints sizeHints; memset(&sizeHints, 0, sizeof(sizeHints)); - if (!view->resizable) { + if (!view->hints.resizable) { sizeHints.flags = PMinSize|PMaxSize; sizeHints.min_width = view->width; sizeHints.min_height = view->height; diff --git a/pugl/pugl_x11_gl.c b/pugl/pugl_x11_gl.c index d6242f2..6c007b1 100644 --- a/pugl/pugl_x11_gl.c +++ b/pugl/pugl_x11_gl.c @@ -22,62 +22,117 @@ #include <GL/glx.h> #include <stdlib.h> +#include <stdio.h> typedef struct { - GLXContext ctx; - int doubleBuffered; + 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; - - /** Attributes for double-buffered RGBA. */ - static int attrListDbl[] = { GLX_RGBA, - GLX_DOUBLEBUFFER, True, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_DEPTH_SIZE, 16, - /* GLX_SAMPLE_BUFFERS , 1, */ - /* GLX_SAMPLES , 4, */ - None }; - - /** Attributes for single-buffered RGBA. */ - static int attrListSgl[] = { GLX_RGBA, - GLX_DOUBLEBUFFER, False, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_DEPTH_SIZE, 16, - /* GLX_SAMPLE_BUFFERS , 1, */ - /* GLX_SAMPLES , 4, */ - None }; - - /** Null-terminated list of attributes in order of preference. */ - static int* attrLists[] = { attrListDbl, attrListSgl, NULL }; - - if (view->ctx_type & PUGL_GL) { - for (int* attr = *attrLists; !impl->vi && *attr; ++attr) { - impl->vi = glXChooseVisual(impl->display, impl->screen, attr); - } + 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, (view->hints.samples + ? GLX_DONT_CARE + : 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)); + return 0; } static int puglX11GlCreate(PuglView* view) { - PuglInternals* const impl = view->impl; - - PuglX11GlSurface* surface = (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface)); + 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( + (GLubyte*)"glXCreateContextAttribsARB"); impl->surface = surface; - surface->ctx = glXCreateContext(impl->display, impl->vi, 0, GL_TRUE); - glXGetConfig( - impl->display, impl->vi, GLX_DOUBLEBUFFER, &surface->doubleBuffered); + 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; } @@ -86,9 +141,11 @@ static int puglX11GlDestroy(PuglView* view) { PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; - glXDestroyContext(view->impl->display, surface->ctx); - free(surface); - view->impl->surface = NULL; + if (surface) { + glXDestroyContext(view->impl->display, surface->ctx); + free(surface); + view->impl->surface = NULL; + } return 0; } @@ -110,7 +167,7 @@ puglX11GlLeave(PuglView* view, bool flush) } glXMakeCurrent(view->impl->display, None, NULL); - if (surface->doubleBuffered) { + if (surface->double_buffered) { glXSwapBuffers(view->impl->display, view->impl->win); } |