1 /*
2  * Copyright © 2013 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <string.h>
26 #include <stdio.h>
27 
28 #include "dispatch_common.h"
29 
30 /**
31  * If we can determine the GLX version from the current context, then
32  * return that, otherwise return a version that will just send us on
33  * to dlsym() or get_proc_address().
34  */
35 int
epoxy_conservative_glx_version(void)36 epoxy_conservative_glx_version(void)
37 {
38     Display *dpy = glXGetCurrentDisplay();
39     GLXContext ctx = glXGetCurrentContext();
40     int screen;
41 
42     if (!dpy || !ctx)
43         return 14;
44 
45     glXQueryContext(dpy, ctx, GLX_SCREEN, &screen);
46 
47     return epoxy_glx_version(dpy, screen);
48 }
49 
50 
51 /**
52  * @brief Returns the version of GLX we are using
53  *
54  * The version is encoded as:
55  *
56  * ```
57  *
58  *   version = major * 10 + minor
59  *
60  * ```
61  *
62  * So it can be easily used for version comparisons.
63  *
64  * @param dpy The X11 display
65  * @param screen The X11 screen
66  *
67  * @return The encoded version of GLX we are using
68  *
69  * @see epoxy_gl_version()
70  */
71 int
epoxy_glx_version(Display * dpy,int screen)72 epoxy_glx_version(Display *dpy, int screen)
73 {
74     int server_major, server_minor;
75     int client_major, client_minor;
76     int server, client;
77     const char *version_string;
78     int ret;
79 
80     version_string = glXQueryServerString(dpy, screen, GLX_VERSION);
81     if (!version_string)
82         return 0;
83 
84     ret = sscanf(version_string, "%d.%d", &server_major, &server_minor);
85     assert(ret == 2);
86     server = server_major * 10 + server_minor;
87 
88     version_string = glXGetClientString(dpy, GLX_VERSION);
89     if (!version_string)
90         return 0;
91 
92     ret = sscanf(version_string, "%d.%d", &client_major, &client_minor);
93     assert(ret == 2);
94     client = client_major * 10 + client_minor;
95 
96     if (client < server)
97         return client;
98     else
99         return server;
100 }
101 
102 /**
103  * If we can determine the GLX extension support from the current
104  * context, then return that, otherwise give the answer that will just
105  * send us on to get_proc_address().
106  */
107 bool
epoxy_conservative_has_glx_extension(const char * ext)108 epoxy_conservative_has_glx_extension(const char *ext)
109 {
110     Display *dpy = glXGetCurrentDisplay();
111     GLXContext ctx = glXGetCurrentContext();
112     int screen;
113 
114     if (!dpy || !ctx)
115         return true;
116 
117     glXQueryContext(dpy, ctx, GLX_SCREEN, &screen);
118 
119     return epoxy_has_glx_extension(dpy, screen, ext);
120 }
121 
122 /**
123  * @brief Returns true if the given GLX extension is supported in the current context.
124  *
125  * @param dpy The X11 display
126  * @param screen The X11 screen
127  * @param extension The name of the GLX extension
128  *
129  * @return `true` if the extension is available
130  *
131  * @see epoxy_has_gl_extension()
132  * @see epoxy_has_egl_extension()
133  */
134 bool
epoxy_has_glx_extension(Display * dpy,int screen,const char * ext)135 epoxy_has_glx_extension(Display *dpy, int screen, const char *ext)
136 {
137     /* No, you can't just use glXGetClientString or
138      * glXGetServerString() here.  Those each tell you about one half
139      * of what's needed for an extension to be supported, and
140      * glXQueryExtensionsString() is what gives you the intersection
141      * of the two.
142      */
143     return epoxy_extension_in_string(glXQueryExtensionsString(dpy, screen), ext);
144 }
145 
146 /**
147  * @brief Checks whether GLX is available.
148  *
149  * @param dpy The X11 display
150  *
151  * @return `true` if GLX is available
152  *
153  * @newin{1,4}
154  */
155 bool
epoxy_has_glx(Display * dpy)156 epoxy_has_glx(Display *dpy)
157 {
158 #if !PLATFORM_HAS_GLX
159     return false;
160 #else
161     if (epoxy_load_glx(false, true)) {
162         Bool (* pf_glXQueryExtension) (Display *, int *, int *);
163         int error_base, event_base;
164 
165         pf_glXQueryExtension = epoxy_conservative_glx_dlsym("glXQueryExtension", false);
166         if (pf_glXQueryExtension && pf_glXQueryExtension(dpy, &error_base, &event_base))
167             return true;
168     }
169 
170     return false;
171 #endif /* !PLATFORM_HAS_GLX */
172 }
173