1 /*
2  * Compton - a compositor for X11
3  *
4  * Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
5  *
6  * Copyright (c) 2011-2013, Christopher Jeffrey
7  * See LICENSE for more information.
8  *
9  */
10 
11 #include "common.h"
12 
13 #include <ctype.h>
14 #include <locale.h>
15 
16 #ifdef DEBUG_GLX_ERR
17 
18 /**
19  * Get a textual representation of an OpenGL error.
20  */
21 static inline const char *
glx_dump_err_str(GLenum err)22 glx_dump_err_str(GLenum err) {
23   switch (err) {
24     CASESTRRET(GL_NO_ERROR);
25     CASESTRRET(GL_INVALID_ENUM);
26     CASESTRRET(GL_INVALID_VALUE);
27     CASESTRRET(GL_INVALID_OPERATION);
28     CASESTRRET(GL_INVALID_FRAMEBUFFER_OPERATION);
29     CASESTRRET(GL_OUT_OF_MEMORY);
30     CASESTRRET(GL_STACK_UNDERFLOW);
31     CASESTRRET(GL_STACK_OVERFLOW);
32   }
33 
34   return NULL;
35 }
36 
37 /**
38  * Check for GLX error.
39  *
40  * http://blog.nobel-joergensen.com/2013/01/29/debugging-opengl-using-glgeterror/
41  */
42 static inline void
glx_check_err_(session_t * ps,const char * func,int line)43 glx_check_err_(session_t *ps, const char *func, int line) {
44   if (!ps->psglx->context) return;
45 
46   GLenum err = GL_NO_ERROR;
47 
48   while (GL_NO_ERROR != (err = glGetError())) {
49     print_timestamp(ps);
50     printf("%s():%d: GLX error ", func, line);
51     const char *errtext = glx_dump_err_str(err);
52     if (errtext) {
53       printf_dbg("%s\n", errtext);
54     }
55     else {
56       printf_dbg("%d\n", err);
57     }
58   }
59 }
60 
61 #define glx_check_err(ps) glx_check_err_(ps, __func__, __LINE__)
62 #else
63 #define glx_check_err(ps) ((void) 0)
64 #endif
65 
66 /**
67  * Check if a word is in string.
68  */
69 static inline bool
wd_is_in_str(const char * haystick,const char * needle)70 wd_is_in_str(const char *haystick, const char *needle) {
71   if (!haystick)
72     return false;
73 
74   assert(*needle);
75 
76   const char *pos = haystick - 1;
77   while ((pos = strstr(pos + 1, needle))) {
78     // Continue if it isn't a word boundary
79     if (((pos - haystick) && !isspace(*(pos - 1)))
80         || (strlen(pos) > strlen(needle) && !isspace(pos[strlen(needle)])))
81       continue;
82     return true;
83   }
84 
85   return false;
86 }
87 
88 /**
89  * Check if a GLX extension exists.
90  */
91 static inline bool
glx_hasglxext(session_t * ps,const char * ext)92 glx_hasglxext(session_t *ps, const char *ext) {
93   const char *glx_exts = glXQueryExtensionsString(ps->dpy, ps->scr);
94   if (!glx_exts) {
95     printf_errf("(): Failed get GLX extension list.");
96     return false;
97   }
98 
99   bool found = wd_is_in_str(glx_exts, ext);
100   if (!found)
101     printf_errf("(): Missing GLX extension %s.", ext);
102 
103   return found;
104 }
105 
106 /**
107  * Check if a GLX extension exists.
108  */
109 static inline bool
glx_hasglext(session_t * ps,const char * ext)110 glx_hasglext(session_t *ps, const char *ext) {
111   const char *gl_exts = (const char *) glGetString(GL_EXTENSIONS);
112   if (!gl_exts) {
113     printf_errf("(): Failed get GL extension list.");
114     return false;
115   }
116 
117   bool found = wd_is_in_str(gl_exts, ext);
118   if (!found)
119     printf_errf("(): Missing GL extension %s.", ext);
120 
121   return found;
122 }
123 
124 static inline XVisualInfo *
get_visualinfo_from_visual(session_t * ps,Visual * visual)125 get_visualinfo_from_visual(session_t *ps, Visual *visual) {
126   XVisualInfo vreq = { .visualid = XVisualIDFromVisual(visual) };
127   int nitems = 0;
128 
129   return XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems);
130 }
131 
132 static bool
133 glx_update_fbconfig(session_t *ps);
134 
135 static int
136 glx_cmp_fbconfig(session_t *ps,
137     const glx_fbconfig_t *pfbc_a, const glx_fbconfig_t *pfbc_b);
138 
139 static void
140 glx_render_color(session_t *ps, int dx, int dy, int width, int height, int z,
141     XserverRegion reg_tgt, const reg_data_t *pcache_reg);
142 
143 static void
144 glx_render_dots(session_t *ps, int dx, int dy, int width, int height, int z,
145     XserverRegion reg_tgt, const reg_data_t *pcache_reg);
146