diff options
Diffstat (limited to 'utils/visual-gl.c')
-rw-r--r-- | utils/visual-gl.c | 350 |
1 files changed, 320 insertions, 30 deletions
diff --git a/utils/visual-gl.c b/utils/visual-gl.c index c4b940b..cca4ecf 100644 --- a/utils/visual-gl.c +++ b/utils/visual-gl.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1999-2018 by Jamie Zawinski <jwz@jwz.org> +/* xscreensaver, Copyright © 1999-2021 Jamie Zawinski <jwz@jwz.org> * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -21,21 +21,78 @@ */ #include "utils.h" -#include "visual.h" #include "resources.h" #ifdef HAVE_GL # include <GL/gl.h> -# include <GL/glx.h> +# ifdef HAVE_EGL +# include <EGL/egl.h> +# include <EGL/eglext.h> +# else +# include <GL/glx.h> +# endif #endif /* HAVE_GL */ +#include "visual.h" /* after EGL/egl.h */ + +#undef countof +#define countof(x) (sizeof(x)/sizeof(*(x))) + + extern char *progname; + Visual * get_gl_visual (Screen *screen) { #ifdef HAVE_GL + Display *dpy = DisplayOfScreen (screen); + +# ifdef HAVE_EGL + + Visual *v; + EGLint vid; + EGLDisplay *egl_display; + EGLConfig egl_config = 0; + int egl_major = -1, egl_minor = -1; + + /* This is re-used, no need to close it. */ + egl_display = eglGetDisplay ((EGLNativeDisplayType) dpy); + if (!egl_display) + { + fprintf (stderr, "%s: eglGetDisplay failed\n", progname); + return 0; + } + + if (! eglInitialize (egl_display, &egl_major, &egl_minor)) + { + fprintf (stderr, "%s: eglInitialize failed\n", progname); + abort(); + } + + /* Get the best EGL config on any visual, then see what visual it used. */ + get_egl_config (dpy, egl_display, -1, &egl_config); + if (!egl_config) abort(); + + if (!eglGetConfigAttrib (egl_display, egl_config, + EGL_NATIVE_VISUAL_ID, &vid)) + { + fprintf (stderr, "%s: EGL: no native visual ID\n", progname); + abort(); + } + + v = id_to_visual (screen, vid); + if (!v) + { + fprintf (stderr, "%s: EGL: no X11 visual 0x%x\n", progname, vid); + abort(); + } + + return v; + +# else /* !HAVE_EGL -- GLX */ + int screen_num = screen_number (screen); # define R GLX_RED_SIZE @@ -61,7 +118,6 @@ get_gl_visual (Screen *screen) # define SM GL_SAMPLES # endif - int attrs[][40] = { # ifdef SB /* rgba double stencil multisample */ { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,8, 0 }, @@ -107,12 +163,134 @@ get_gl_visual (Screen *screen) return v; } } + +# endif /* !HAVE_EGL -- GLX */ #endif /* !HAVE_GL */ return 0; } +#ifdef HAVE_EGL +/* An X11 "visual" is an object that encapsulates the available display + formats: color mapping, depth and so on. So is a GLE "config". + So why isn't there a one-to-one mapping between visuals and configs? + Once again, I can only assume the answer is that the people responsible + for every post-2002 version of the OpenGL specification are incompetent. + + Under GLX, there will be multiple X11 visuals that appear (and behave) + identically to X11 programs, code but that have different GL parameters. + Two RGB visuals might have different alpha, depth, or stencil sizes, + for example, that would matter to a GL program but not to an X11 program. + + But EGL has dozens of 'configs' for each visual, so we can't just pass + around a Window and a Visual to describe the display parameters: we need + to pass around the 'config' as well. Or, do what we do here, have both + sides use the same code to convert a visual to the best 'config'. + (It goes down a list of parameter settings, from higher quality to lower, + and takes the first config that matches.) + + SGI solved this problem in like 1988, and like so many things, GLES went + and fucked it all up again. + */ +void +get_egl_config (Display *dpy, EGLDisplay *egl_display, + EGLint x11_visual_id, EGLConfig *egl_config) +{ +# define COMMON \ + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, \ + EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER +# define R EGL_RED_SIZE +# define G EGL_GREEN_SIZE +# define B EGL_BLUE_SIZE +# define A EGL_ALPHA_SIZE +# define D EGL_DEPTH_SIZE +# define I EGL_BUFFER_SIZE +# define ST EGL_STENCIL_SIZE +# define SB EGL_SAMPLE_BUFFERS +# define SM EGL_SAMPLES + + const EGLint templates[][40] = { +# ifdef SB + { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, SB,1, SM,8, EGL_NONE }, + { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, SB,1, SM,6, EGL_NONE }, + { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, SB,1, SM,4, EGL_NONE }, + { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, SB,1, SM,2, EGL_NONE }, +# define SB_COUNT 4 /* #### Kludgey count of preceeding lines! */ +# endif + { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, EGL_NONE }, /* rgba stencil */ + { COMMON, R,8, G,8, B,8, D,8, ST,1, EGL_NONE }, /* rgb stencil */ + { COMMON, R,4, G,4, B,4, D,4, ST,1, EGL_NONE }, + { COMMON, R,2, G,2, B,2, D,2, ST,1, EGL_NONE }, + { COMMON, R,8, G,8, B,8, A,8, D,8, EGL_NONE }, /* rgba */ + { COMMON, R,8, G,8, B,8, D,8, EGL_NONE }, /* rgb */ + { COMMON, R,4, G,4, B,4, D,4, EGL_NONE }, + { COMMON, R,2, G,2, B,2, D,2, EGL_NONE }, + { COMMON, R,1, G,1, B,1, D,1, EGL_NONE } /* monochrome */ + }; + EGLint attrs[40]; + EGLint nconfig; + int i, j, k, iter, pass; + Bool glslp; + + i = 0; +# ifdef SB + if (! get_boolean_resource (dpy, "multiSample", "MultiSample")) + i = SB_COUNT; /* skip over the multibuffer entries in 'attrs' */ +# endif /* SB */ + + glslp = get_boolean_resource (dpy, "prefersGLSL", "PrefersGLSL"); + iter = (glslp ? 2 : 1); + + *egl_config = 0; + for (pass = 0; pass < iter; pass++) + { + for (; i < countof(templates); i++) + { + for (j = 0, k = 0; templates[i][j] != EGL_NONE; j += 2) + { + attrs[k++] = templates[i][j]; + attrs[k++] = templates[i][j+1]; + } + + attrs[k++] = EGL_RENDERABLE_TYPE; +# ifdef HAVE_GLES3 + if (glslp && pass == 0) + attrs[k++] = EGL_OPENGL_ES3_BIT; + else + attrs[k++] = EGL_OPENGL_ES_BIT; +# elif defined(HAVE_JWZGLES) + attrs[k++] = EGL_OPENGL_ES_BIT; +# else + attrs[k++] = EGL_OPENGL_BIT; +# endif + + if (x11_visual_id != -1) + { + attrs[k++] = EGL_NATIVE_VISUAL_ID; + attrs[k++] = x11_visual_id; + } + + attrs[k++] = EGL_NONE; + + nconfig = -1; + if (eglChooseConfig (egl_display, attrs, egl_config, 1, &nconfig) + && nconfig == 1) + break; + } + if (i < countof(templates)) + break; + } + + if (! *egl_config) + { + fprintf (stderr, "%s: eglChooseConfig: no configs found\n", progname); + abort(); + } +} +#endif /* HAVE_EGL */ + + void describe_gl_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p) @@ -121,8 +299,13 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual, #ifdef HAVE_GL { +# ifdef HAVE_EGL + EGLDisplay *egl_display; + EGLConfig config = 0; +# else /* !HAVE_EGL -- GLX */ int status; int value = False; +# endif /* !HAVE_EGL -- GLX */ Display *dpy = DisplayOfScreen (screen); XVisualInfo vi_in, *vi_out; @@ -134,6 +317,108 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual, &vi_in, &out_count); if (! vi_out) abort (); +# ifdef HAVE_EGL + + /* This is re-used, no need to close it. */ + egl_display = eglGetPlatformDisplay (EGL_PLATFORM_X11_KHR, + (EGLNativeDisplayType) dpy, NULL); + if (!egl_display) + { + fprintf (stderr, "%s: eglGetPlatformDisplay failed\n", progname); + return; + } + + get_egl_config (dpy, egl_display, vi_out->visualid, &config); + if (!config) + { + fprintf (stderr, "%s: no matching EGL config for X11 visual 0x%lx\n", + progname, vi_out->visualid); + abort(); + } + + { + int i; + const struct { int hexp; EGLint i; const char *s; } fields[] = { + { 1, EGL_CONFIG_ID, "config ID:" }, + { 1, EGL_CONFIG_CAVEAT, "caveat:" }, + { 1, EGL_CONFORMANT, "conformant:" }, + { 0, EGL_COLOR_BUFFER_TYPE, "buffer type:" }, + { 0, EGL_RED_SIZE, "color size:" }, + { 0, EGL_TRANSPARENT_RED_VALUE, "transparency:" }, + { 0, EGL_BUFFER_SIZE, "buffer size:" }, + { 0, EGL_DEPTH_SIZE, "depth size:" }, + { 0, EGL_LUMINANCE_SIZE, "lum size:" }, + { 0, EGL_STENCIL_SIZE, "stencil size:" }, + { 0, EGL_ALPHA_MASK_SIZE, "alpha mask:" }, + { 0, EGL_LEVEL, "level:" }, + { 0, EGL_SAMPLES, "samples:" }, + { 0, EGL_SAMPLE_BUFFERS, "sample bufs:" }, + { 0, EGL_NATIVE_RENDERABLE, "native render:" }, + { 1, EGL_NATIVE_VISUAL_TYPE, "native type:" }, + { 1, EGL_RENDERABLE_TYPE, "render type:" }, + { 0, EGL_SURFACE_TYPE, "surface type:" }, + { 0, EGL_BIND_TO_TEXTURE_RGB, "bind RGB:" }, + { 0, EGL_BIND_TO_TEXTURE_RGBA, "bind RGBA:" }, + { 0, EGL_MAX_PBUFFER_WIDTH, "buffer width:" }, + { 0, EGL_MAX_PBUFFER_HEIGHT, "buffer height:" }, + { 0, EGL_MAX_PBUFFER_PIXELS, "buffer pixels:" }, + { 0, EGL_MAX_SWAP_INTERVAL, "max swap:" }, + { 0, EGL_MIN_SWAP_INTERVAL, "min swap:" }, + }; + EGLint r=0, g=0, b=0, a=0, tt=0, tr=0, tg=0, tb=0; + eglGetConfigAttrib (egl_display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib (egl_display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib (egl_display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib (egl_display, config, EGL_ALPHA_SIZE, &a); + eglGetConfigAttrib (egl_display, config, EGL_TRANSPARENT_TYPE, &tt); + eglGetConfigAttrib (egl_display, config, EGL_TRANSPARENT_RED_VALUE, &tr); + eglGetConfigAttrib (egl_display, config, EGL_TRANSPARENT_GREEN_VALUE,&tg); + eglGetConfigAttrib (egl_display, config, EGL_TRANSPARENT_BLUE_VALUE, &tb); + for (i = 0; i < countof(fields); i++) + { + EGLint v = 0; + char s[100]; + eglGetConfigAttrib (egl_display, config, fields[i].i, &v); + if (fields[i].i == EGL_RED_SIZE) + sprintf (s, "%d, %d, %d, %d", r, g, b, a); + else if (fields[i].i == EGL_TRANSPARENT_RED_VALUE && tt != EGL_NONE) + sprintf (s, "%d, %d, %d", tr, tg, tb); + else if (fields[i].i == EGL_CONFIG_CAVEAT) + strcpy (s, (v == EGL_NONE ? "none" : + v == EGL_SLOW_CONFIG ? "slow" : +# ifdef EGL_NON_CONFORMANT + v == EGL_NON_CONFORMANT ? "non-conformant" : +# endif + "???")); + else if (fields[i].i == EGL_COLOR_BUFFER_TYPE) + strcpy (s, (v == EGL_RGB_BUFFER ? "RGB" : + v == EGL_LUMINANCE_BUFFER ? "luminance" : + "???")); + else if (fields[i].i == EGL_CONFORMANT || + fields[i].i == EGL_RENDERABLE_TYPE) + { + sprintf (s, "0x%02x", v); + if (v & EGL_OPENGL_BIT) strcat (s, " OpenGL"); + if (v & EGL_OPENGL_ES_BIT) strcat (s, " GLES-1.x"); + if (v & EGL_OPENGL_ES2_BIT) strcat (s, " GLES-2.0"); +# ifdef EGL_OPENGL_ES3_BIT + if (v & EGL_OPENGL_ES3_BIT) strcat (s, " GLES-3.0"); +# endif + if (v & EGL_OPENVG_BIT) strcat (s, " OpenVG"); + } + else if (fields[i].hexp) + sprintf (s, "0x%02x", v); + else if (v) + sprintf (s, "%d", v); + else + *s = 0; + + if (*s) fprintf (f, " EGL %-14s %s\n", fields[i].s, s); + } + } + +# else /* !HAVE_EGL -- GLX */ + status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value); if (status == GLX_NO_EXTENSION) @@ -146,7 +431,7 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual, if (!glXGetConfig (dpy, vi_out, GLX_LEVEL, &value) && value != 0) - printf (" GLX level: %d\n", value); + fprintf (f, " GLX level: %d\n", value); if (!glXGetConfig (dpy, vi_out, GLX_RGBA, &value) && value) { @@ -155,22 +440,22 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual, glXGetConfig (dpy, vi_out, GLX_GREEN_SIZE, &g); glXGetConfig (dpy, vi_out, GLX_BLUE_SIZE, &b); glXGetConfig (dpy, vi_out, GLX_ALPHA_SIZE, &a); - printf (" GLX type: RGBA (%2d, %2d, %2d, %2d)\n", - r, g, b, a); + fprintf (f, " GLX type: RGBA (%2d, %2d, %2d, %2d)\n", + r, g, b, a); r=0, g=0, b=0, a=0; glXGetConfig (dpy, vi_out, GLX_ACCUM_RED_SIZE, &r); glXGetConfig (dpy, vi_out, GLX_ACCUM_GREEN_SIZE, &g); glXGetConfig (dpy, vi_out, GLX_ACCUM_BLUE_SIZE, &b); glXGetConfig (dpy, vi_out, GLX_ACCUM_ALPHA_SIZE, &a); - printf (" GLX accum: RGBA (%2d, %2d, %2d, %2d)\n", - r, g, b, a); + fprintf (f, " GLX accum: RGBA (%2d, %2d, %2d, %2d)\n", + r, g, b, a); } else { value = 0; glXGetConfig (dpy, vi_out, GLX_BUFFER_SIZE, &value); - printf (" GLX type: indexed (%d)\n", value); + fprintf (f, " GLX type: indexed (%d)\n", value); } # ifndef GLX_NONE_EXT /* Hooray for gratuitious name changes. */ @@ -189,36 +474,36 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual, if (!glXGetConfig (dpy, vi_out, GLX_VISUAL_CAVEAT_EXT, &value) && value != GLX_NONE_EXT) # ifdef GLX_NON_CONFORMANT_EXT - printf (" GLX rating: %s\n", - (value == GLX_NONE_EXT ? "none" : - value == GLX_SLOW_VISUAL_EXT ? "slow" : - value == GLX_NON_CONFORMANT_EXT ? "non-conformant" : - "???")); + fprintf (f, " GLX rating: %s\n", + (value == GLX_NONE_EXT ? "none" : + value == GLX_SLOW_VISUAL_EXT ? "slow" : + value == GLX_NON_CONFORMANT_EXT ? "non-conformant" : + "???"); # else - printf (" GLX rating: %s\n", - (value == GLX_NONE_EXT ? "none" : - value == GLX_SLOW_VISUAL_EXT ? "slow" : - "???")); + fprintf (f, " GLX rating: %s\n", + (value == GLX_NONE_EXT ? "none" : + value == GLX_SLOW_VISUAL_EXT ? "slow" : + "???")); # endif /* GLX_NON_CONFORMANT_EXT */ # endif /* GLX_VISUAL_CAVEAT_EXT */ if (!glXGetConfig (dpy, vi_out, GLX_DOUBLEBUFFER, &value)) - printf (" GLX double-buffer: %s\n", (value ? "yes" : "no")); + fprintf (f, " GLX double-buffer: %s\n", (value ? "yes" : "no")); if (!glXGetConfig (dpy, vi_out, GLX_STEREO, &value) && value) - printf (" GLX stereo: %s\n", (value ? "yes" : "no")); + fprintf (f, " GLX stereo: %s\n", (value ? "yes" : "no")); if (!glXGetConfig (dpy, vi_out, GLX_AUX_BUFFERS, &value) && value != 0) - printf (" GLX aux buffers: %d\n", value); + fprintf (f, " GLX aux buffers: %d\n", value); if (!glXGetConfig (dpy, vi_out, GLX_DEPTH_SIZE, &value)) - printf (" GLX depth size: %d\n", value); + fprintf (f, " GLX depth size: %d\n", value); if (!glXGetConfig (dpy, vi_out, GLX_STENCIL_SIZE, &value) && value != 0) - printf (" GLX stencil size: %d\n", value); + fprintf (f, " GLX stencil size: %d\n", value); # ifdef SB /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */ if (!glXGetConfig (dpy, vi_out, SB, &value) && @@ -226,7 +511,7 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual, { int bufs = value; if (!glXGetConfig (dpy, vi_out, SM, &value)) - printf (" GLX multisample: %d, %d\n", bufs, value); + fprintf (f, " GLX multisample: %d, %d\n", bufs, value); } # endif /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */ @@ -234,12 +519,12 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual, value != GLX_NONE_EXT) { if (value == GLX_NONE_EXT) - printf (" GLX transparency: none\n"); + fprintf (f, " GLX transparency: none\n"); else if (value == GLX_TRANSPARENT_INDEX_EXT) { if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_INDEX_VALUE_EXT, &value)) - printf (" GLX transparency: indexed (%d)\n", value); + fprintf (f, " GLX transparency: indexed (%d)\n", value); } else if (value == GLX_TRANSPARENT_RGB_EXT) { @@ -248,10 +533,11 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual, glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_GREEN_VALUE_EXT, &g); glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_BLUE_VALUE_EXT, &b); glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_ALPHA_VALUE_EXT, &a); - printf (" GLX transparency: RGBA (%2d, %2d, %2d, %2d)\n", - r, g, b, a); + fprintf (f, " GLX transparency: RGBA (%2d, %2d, %2d, %2d)\n", + r, g, b, a); } } +# endif /* !HAVE_EGL */ } #endif /* HAVE_GL */ } @@ -262,13 +548,15 @@ validate_gl_visual (FILE *out, Screen *screen, const char *window_desc, Visual *visual) { #ifdef HAVE_GL +# ifndef HAVE_EGL int status; int value = False; + unsigned int id; +# endif Display *dpy = DisplayOfScreen (screen); XVisualInfo vi_in, *vi_out; int out_count; - unsigned int id; vi_in.screen = screen_number (screen); vi_in.visualid = XVisualIDFromVisual (visual); @@ -276,6 +564,7 @@ validate_gl_visual (FILE *out, Screen *screen, const char *window_desc, &vi_in, &out_count); if (! vi_out) abort (); +# ifndef HAVE_EGL status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value); id = (unsigned int) vi_out->visualid; @@ -295,6 +584,7 @@ validate_gl_visual (FILE *out, Screen *screen, const char *window_desc, return False; } else +# endif /* !HAVE_EGL */ { return True; } |