1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // FunctionsGLX.cpp: Implements the FunctionsGLX class.
8
9 #define ANGLE_SKIP_GLX_DEFINES 1
10 #include "libANGLE/renderer/gl/glx/FunctionsGLX.h"
11 #undef ANGLE_SKIP_GLX_DEFINES
12
13 // We can only include glx.h in files which do not include ANGLE's GLES
14 // headers, to avoid doubly-defined GLenum macros, typedefs, etc.
15 #include <GL/glx.h>
16
17 #include <dlfcn.h>
18 #include <algorithm>
19
20 #include "common/string_utils.h"
21 #include "libANGLE/renderer/gl/glx/functionsglx_typedefs.h"
22
23 namespace rx
24 {
25
26 void *FunctionsGLX::sLibHandle = nullptr;
27
28 template <typename T>
GetProc(PFNGETPROCPROC getProc,T * member,const char * name)29 static bool GetProc(PFNGETPROCPROC getProc, T *member, const char *name)
30 {
31 *member = reinterpret_cast<T>(getProc(name));
32 return *member != nullptr;
33 }
34
35 struct FunctionsGLX::GLXFunctionTable
36 {
GLXFunctionTablerx::FunctionsGLX::GLXFunctionTable37 GLXFunctionTable()
38 : createContextPtr(nullptr),
39 destroyContextPtr(nullptr),
40 makeCurrentPtr(nullptr),
41 swapBuffersPtr(nullptr),
42 queryExtensionPtr(nullptr),
43 queryVersionPtr(nullptr),
44 getCurrentContextPtr(nullptr),
45 getCurrentDrawablePtr(nullptr),
46 waitXPtr(nullptr),
47 waitGLPtr(nullptr),
48 getClientStringPtr(nullptr),
49 queryExtensionsStringPtr(nullptr),
50 getFBConfigsPtr(nullptr),
51 chooseFBConfigPtr(nullptr),
52 getFBConfigAttribPtr(nullptr),
53 getVisualFromFBConfigPtr(nullptr),
54 createWindowPtr(nullptr),
55 destroyWindowPtr(nullptr),
56 createPbufferPtr(nullptr),
57 destroyPbufferPtr(nullptr),
58 queryDrawablePtr(nullptr),
59 createPixmapPtr(nullptr),
60 destroyPixmapPtr(nullptr),
61 createContextAttribsARBPtr(nullptr),
62 swapIntervalEXTPtr(nullptr),
63 swapIntervalMESAPtr(nullptr),
64 swapIntervalSGIPtr(nullptr),
65 getSyncValuesOMLPtr(nullptr),
66 getMscRateOMLPtr(nullptr),
67 bindTexImageEXTPtr(nullptr),
68 releaseTexImageEXTPtr(nullptr)
69 {}
70
71 // GLX 1.0
72 PFNGLXCREATECONTEXTPROC createContextPtr;
73 PFNGLXDESTROYCONTEXTPROC destroyContextPtr;
74 PFNGLXMAKECURRENTPROC makeCurrentPtr;
75 PFNGLXSWAPBUFFERSPROC swapBuffersPtr;
76 PFNGLXQUERYEXTENSIONPROC queryExtensionPtr;
77 PFNGLXQUERYVERSIONPROC queryVersionPtr;
78 PFNGLXGETCURRENTCONTEXTPROC getCurrentContextPtr;
79 PFNGLXGETCURRENTDRAWABLEPROC getCurrentDrawablePtr;
80 PFNGLXWAITXPROC waitXPtr;
81 PFNGLXWAITGLPROC waitGLPtr;
82
83 // GLX 1.1
84 PFNGLXGETCLIENTSTRINGPROC getClientStringPtr;
85 PFNGLXQUERYEXTENSIONSSTRINGPROC queryExtensionsStringPtr;
86
87 // GLX 1.3
88 PFNGLXGETFBCONFIGSPROC getFBConfigsPtr;
89 PFNGLXCHOOSEFBCONFIGPROC chooseFBConfigPtr;
90 PFNGLXGETFBCONFIGATTRIBPROC getFBConfigAttribPtr;
91 PFNGLXGETVISUALFROMFBCONFIGPROC getVisualFromFBConfigPtr;
92 PFNGLXCREATEWINDOWPROC createWindowPtr;
93 PFNGLXDESTROYWINDOWPROC destroyWindowPtr;
94 PFNGLXCREATEPBUFFERPROC createPbufferPtr;
95 PFNGLXDESTROYPBUFFERPROC destroyPbufferPtr;
96 PFNGLXQUERYDRAWABLEPROC queryDrawablePtr;
97 PFNGLXCREATEPIXMAPPROC createPixmapPtr;
98 PFNGLXDESTROYPIXMAPPROC destroyPixmapPtr;
99
100 // GLX_ARB_create_context
101 PFNGLXCREATECONTEXTATTRIBSARBPROC createContextAttribsARBPtr;
102
103 // GLX_EXT_swap_control
104 PFNGLXSWAPINTERVALEXTPROC swapIntervalEXTPtr;
105
106 // GLX_MESA_swap_control
107 PFNGLXSWAPINTERVALMESAPROC swapIntervalMESAPtr;
108
109 // GLX_SGI_swap_control
110 PFNGLXSWAPINTERVALSGIPROC swapIntervalSGIPtr;
111
112 // GLX_OML_sync_control
113 PFNGLXGETSYNCVALUESOMLPROC getSyncValuesOMLPtr;
114 PFNGLXGETMSCRATEOMLPROC getMscRateOMLPtr;
115
116 // GLX_EXT_texture_from_pixmap
117 PFNGLXBINDTEXIMAGEEXTPROC bindTexImageEXTPtr;
118 PFNGLXRELEASETEXIMAGEEXTPROC releaseTexImageEXTPtr;
119 };
120
FunctionsGLX()121 FunctionsGLX::FunctionsGLX()
122 : majorVersion(0),
123 minorVersion(0),
124 mXDisplay(nullptr),
125 mXScreen(-1),
126 mFnPtrs(new GLXFunctionTable())
127 {}
128
~FunctionsGLX()129 FunctionsGLX::~FunctionsGLX()
130 {
131 delete mFnPtrs;
132 terminate();
133 }
134
initialize(Display * xDisplay,int screen,std::string * errorString)135 bool FunctionsGLX::initialize(Display *xDisplay, int screen, std::string *errorString)
136 {
137 terminate();
138 mXDisplay = xDisplay;
139 mXScreen = screen;
140
141 #if !defined(ANGLE_LINK_GLX)
142 // Some OpenGL implementations can't handle having this library
143 // handle closed while there's any X window still open against
144 // which a GLXWindow was ever created.
145 if (!sLibHandle)
146 {
147 sLibHandle = dlopen("libGL.so.1", RTLD_NOW);
148 if (!sLibHandle)
149 {
150 *errorString = std::string("Could not dlopen libGL.so.1: ") + dlerror();
151 return false;
152 }
153 }
154
155 getProc = reinterpret_cast<PFNGETPROCPROC>(dlsym(sLibHandle, "glXGetProcAddress"));
156 if (!getProc)
157 {
158 getProc = reinterpret_cast<PFNGETPROCPROC>(dlsym(sLibHandle, "glXGetProcAddressARB"));
159 }
160 if (!getProc)
161 {
162 *errorString = "Could not retrieve glXGetProcAddress";
163 return false;
164 }
165 #else
166 getProc = reinterpret_cast<PFNGETPROCPROC>(glXGetProcAddress);
167 #endif
168
169 #define GET_PROC_OR_ERROR(MEMBER, NAME) \
170 do \
171 { \
172 if (!GetProc(getProc, MEMBER, #NAME)) \
173 { \
174 *errorString = "Could not load GLX entry point " #NAME; \
175 return false; \
176 } \
177 } while (0)
178 #if !defined(ANGLE_LINK_GLX)
179 # define GET_FNPTR_OR_ERROR(MEMBER, NAME) GET_PROC_OR_ERROR(MEMBER, NAME)
180 #else
181 # define GET_FNPTR_OR_ERROR(MEMBER, NAME) *MEMBER = NAME
182 #endif
183
184 // GLX 1.0
185 GET_FNPTR_OR_ERROR(&mFnPtrs->createContextPtr, glXCreateContext);
186 GET_FNPTR_OR_ERROR(&mFnPtrs->destroyContextPtr, glXDestroyContext);
187 GET_FNPTR_OR_ERROR(&mFnPtrs->makeCurrentPtr, glXMakeCurrent);
188 GET_FNPTR_OR_ERROR(&mFnPtrs->swapBuffersPtr, glXSwapBuffers);
189 GET_FNPTR_OR_ERROR(&mFnPtrs->queryExtensionPtr, glXQueryExtension);
190 GET_FNPTR_OR_ERROR(&mFnPtrs->queryVersionPtr, glXQueryVersion);
191 GET_FNPTR_OR_ERROR(&mFnPtrs->getCurrentContextPtr, glXGetCurrentContext);
192 GET_FNPTR_OR_ERROR(&mFnPtrs->getCurrentDrawablePtr, glXGetCurrentDrawable);
193 GET_FNPTR_OR_ERROR(&mFnPtrs->waitXPtr, glXWaitX);
194 GET_FNPTR_OR_ERROR(&mFnPtrs->waitGLPtr, glXWaitGL);
195
196 // GLX 1.1
197 GET_FNPTR_OR_ERROR(&mFnPtrs->getClientStringPtr, glXGetClientString);
198 GET_FNPTR_OR_ERROR(&mFnPtrs->queryExtensionsStringPtr, glXQueryExtensionsString);
199
200 // Check we have a working GLX
201 {
202 int errorBase;
203 int eventBase;
204 if (!queryExtension(&errorBase, &eventBase))
205 {
206 *errorString = "GLX is not present.";
207 return false;
208 }
209 }
210
211 // Check we have a supported version of GLX
212 if (!queryVersion(&majorVersion, &minorVersion))
213 {
214 *errorString = "Could not query the GLX version.";
215 return false;
216 }
217 if (majorVersion != 1 || minorVersion < 3)
218 {
219 *errorString = "Unsupported GLX version (requires at least 1.3).";
220 return false;
221 }
222
223 const char *extensions = queryExtensionsString();
224 if (!extensions)
225 {
226 *errorString = "glXQueryExtensionsString returned NULL";
227 return false;
228 }
229 angle::SplitStringAlongWhitespace(extensions, &mExtensions);
230
231 // GLX 1.3
232 GET_FNPTR_OR_ERROR(&mFnPtrs->getFBConfigsPtr, glXGetFBConfigs);
233 GET_FNPTR_OR_ERROR(&mFnPtrs->chooseFBConfigPtr, glXChooseFBConfig);
234 GET_FNPTR_OR_ERROR(&mFnPtrs->getFBConfigAttribPtr, glXGetFBConfigAttrib);
235 GET_FNPTR_OR_ERROR(&mFnPtrs->getVisualFromFBConfigPtr, glXGetVisualFromFBConfig);
236 GET_FNPTR_OR_ERROR(&mFnPtrs->createWindowPtr, glXCreateWindow);
237 GET_FNPTR_OR_ERROR(&mFnPtrs->destroyWindowPtr, glXDestroyWindow);
238 GET_FNPTR_OR_ERROR(&mFnPtrs->createPbufferPtr, glXCreatePbuffer);
239 GET_FNPTR_OR_ERROR(&mFnPtrs->destroyPbufferPtr, glXDestroyPbuffer);
240 GET_FNPTR_OR_ERROR(&mFnPtrs->queryDrawablePtr, glXQueryDrawable);
241 GET_FNPTR_OR_ERROR(&mFnPtrs->createPixmapPtr, glXCreatePixmap);
242 GET_FNPTR_OR_ERROR(&mFnPtrs->destroyPixmapPtr, glXDestroyPixmap);
243
244 // Extensions
245 if (hasExtension("GLX_ARB_create_context"))
246 {
247 GET_PROC_OR_ERROR(&mFnPtrs->createContextAttribsARBPtr, glXCreateContextAttribsARB);
248 }
249 if (hasExtension("GLX_EXT_swap_control"))
250 {
251 GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalEXTPtr, glXSwapIntervalEXT);
252 }
253 if (hasExtension("GLX_MESA_swap_control"))
254 {
255 GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalMESAPtr, glXSwapIntervalMESA);
256 }
257 if (hasExtension("GLX_SGI_swap_control"))
258 {
259 GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalSGIPtr, glXSwapIntervalSGI);
260 }
261 if (hasExtension("GLX_OML_sync_control"))
262 {
263 GET_PROC_OR_ERROR(&mFnPtrs->getSyncValuesOMLPtr, glXGetSyncValuesOML);
264 GET_PROC_OR_ERROR(&mFnPtrs->getMscRateOMLPtr, glXGetMscRateOML);
265 }
266 if (hasExtension("GLX_EXT_texture_from_pixmap"))
267 {
268 GET_PROC_OR_ERROR(&mFnPtrs->bindTexImageEXTPtr, glXBindTexImageEXT);
269 GET_PROC_OR_ERROR(&mFnPtrs->releaseTexImageEXTPtr, glXReleaseTexImageEXT);
270 }
271
272 #undef GET_FNPTR_OR_ERROR
273 #undef GET_PROC_OR_ERROR
274
275 *errorString = "";
276 return true;
277 }
278
terminate()279 void FunctionsGLX::terminate() {}
280
hasExtension(const char * extension) const281 bool FunctionsGLX::hasExtension(const char *extension) const
282 {
283 return std::find(mExtensions.begin(), mExtensions.end(), extension) != mExtensions.end();
284 }
285
getDisplay() const286 Display *FunctionsGLX::getDisplay() const
287 {
288 return mXDisplay;
289 }
290
getScreen() const291 int FunctionsGLX::getScreen() const
292 {
293 return mXScreen;
294 }
295
296 // GLX functions
297
298 // GLX 1.0
createContext(XVisualInfo * visual,glx::Context share,bool direct) const299 glx::Context FunctionsGLX::createContext(XVisualInfo *visual, glx::Context share, bool direct) const
300 {
301 GLXContext shareCtx = reinterpret_cast<GLXContext>(share);
302 GLXContext context = mFnPtrs->createContextPtr(mXDisplay, visual, shareCtx, direct);
303 return reinterpret_cast<glx::Context>(context);
304 }
destroyContext(glx::Context context) const305 void FunctionsGLX::destroyContext(glx::Context context) const
306 {
307 GLXContext ctx = reinterpret_cast<GLXContext>(context);
308 mFnPtrs->destroyContextPtr(mXDisplay, ctx);
309 }
makeCurrent(glx::Drawable drawable,glx::Context context) const310 Bool FunctionsGLX::makeCurrent(glx::Drawable drawable, glx::Context context) const
311 {
312 GLXContext ctx = reinterpret_cast<GLXContext>(context);
313 return mFnPtrs->makeCurrentPtr(mXDisplay, drawable, ctx);
314 }
swapBuffers(glx::Drawable drawable) const315 void FunctionsGLX::swapBuffers(glx::Drawable drawable) const
316 {
317 mFnPtrs->swapBuffersPtr(mXDisplay, drawable);
318 }
queryExtension(int * errorBase,int * event) const319 Bool FunctionsGLX::queryExtension(int *errorBase, int *event) const
320 {
321 return mFnPtrs->queryExtensionPtr(mXDisplay, errorBase, event);
322 }
queryVersion(int * major,int * minor) const323 Bool FunctionsGLX::queryVersion(int *major, int *minor) const
324 {
325 return mFnPtrs->queryVersionPtr(mXDisplay, major, minor);
326 }
getCurrentContext() const327 glx::Context FunctionsGLX::getCurrentContext() const
328 {
329 GLXContext context = mFnPtrs->getCurrentContextPtr();
330 return reinterpret_cast<glx::Context>(context);
331 }
getCurrentDrawable() const332 glx::Drawable FunctionsGLX::getCurrentDrawable() const
333 {
334 GLXDrawable drawable = mFnPtrs->getCurrentDrawablePtr();
335 return reinterpret_cast<glx::Drawable>(drawable);
336 }
waitX() const337 void FunctionsGLX::waitX() const
338 {
339 mFnPtrs->waitXPtr();
340 }
waitGL() const341 void FunctionsGLX::waitGL() const
342 {
343 mFnPtrs->waitGLPtr();
344 }
345
346 // GLX 1.1
getClientString(int name) const347 const char *FunctionsGLX::getClientString(int name) const
348 {
349 return mFnPtrs->getClientStringPtr(mXDisplay, name);
350 }
351
queryExtensionsString() const352 const char *FunctionsGLX::queryExtensionsString() const
353 {
354 return mFnPtrs->queryExtensionsStringPtr(mXDisplay, mXScreen);
355 }
356
357 // GLX 1.4
getFBConfigs(int * nElements) const358 glx::FBConfig *FunctionsGLX::getFBConfigs(int *nElements) const
359 {
360 GLXFBConfig *configs = mFnPtrs->getFBConfigsPtr(mXDisplay, mXScreen, nElements);
361 return reinterpret_cast<glx::FBConfig *>(configs);
362 }
chooseFBConfig(const int * attribList,int * nElements) const363 glx::FBConfig *FunctionsGLX::chooseFBConfig(const int *attribList, int *nElements) const
364 {
365 GLXFBConfig *configs = mFnPtrs->chooseFBConfigPtr(mXDisplay, mXScreen, attribList, nElements);
366 return reinterpret_cast<glx::FBConfig *>(configs);
367 }
getFBConfigAttrib(glx::FBConfig config,int attribute,int * value) const368 int FunctionsGLX::getFBConfigAttrib(glx::FBConfig config, int attribute, int *value) const
369 {
370 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
371 return mFnPtrs->getFBConfigAttribPtr(mXDisplay, cfg, attribute, value);
372 }
getVisualFromFBConfig(glx::FBConfig config) const373 XVisualInfo *FunctionsGLX::getVisualFromFBConfig(glx::FBConfig config) const
374 {
375 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
376 return mFnPtrs->getVisualFromFBConfigPtr(mXDisplay, cfg);
377 }
createWindow(glx::FBConfig config,Window window,const int * attribList) const378 GLXWindow FunctionsGLX::createWindow(glx::FBConfig config,
379 Window window,
380 const int *attribList) const
381 {
382 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
383 return mFnPtrs->createWindowPtr(mXDisplay, cfg, window, attribList);
384 }
destroyWindow(glx::Window window) const385 void FunctionsGLX::destroyWindow(glx::Window window) const
386 {
387 mFnPtrs->destroyWindowPtr(mXDisplay, window);
388 }
createPbuffer(glx::FBConfig config,const int * attribList) const389 glx::Pbuffer FunctionsGLX::createPbuffer(glx::FBConfig config, const int *attribList) const
390 {
391 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
392 return mFnPtrs->createPbufferPtr(mXDisplay, cfg, attribList);
393 }
destroyPbuffer(glx::Pbuffer pbuffer) const394 void FunctionsGLX::destroyPbuffer(glx::Pbuffer pbuffer) const
395 {
396 mFnPtrs->destroyPbufferPtr(mXDisplay, pbuffer);
397 }
queryDrawable(glx::Drawable drawable,int attribute,unsigned int * value) const398 void FunctionsGLX::queryDrawable(glx::Drawable drawable, int attribute, unsigned int *value) const
399 {
400 mFnPtrs->queryDrawablePtr(mXDisplay, drawable, attribute, value);
401 }
402
createPixmap(glx::FBConfig config,Pixmap pixmap,const int * attribList) const403 glx::Pixmap FunctionsGLX::createPixmap(glx::FBConfig config,
404 Pixmap pixmap,
405 const int *attribList) const
406 {
407 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
408 return mFnPtrs->createPixmapPtr(mXDisplay, cfg, pixmap, attribList);
409 }
destroyPixmap(Pixmap pixmap) const410 void FunctionsGLX::destroyPixmap(Pixmap pixmap) const
411 {
412 mFnPtrs->destroyPixmapPtr(mXDisplay, pixmap);
413 }
414
415 // GLX_ARB_create_context
createContextAttribsARB(glx::FBConfig config,glx::Context shareContext,Bool direct,const int * attribList) const416 glx::Context FunctionsGLX::createContextAttribsARB(glx::FBConfig config,
417 glx::Context shareContext,
418 Bool direct,
419 const int *attribList) const
420 {
421 GLXContext shareCtx = reinterpret_cast<GLXContext>(shareContext);
422 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
423 GLXContext ctx =
424 mFnPtrs->createContextAttribsARBPtr(mXDisplay, cfg, shareCtx, direct, attribList);
425 return reinterpret_cast<glx::Context>(ctx);
426 }
427
swapIntervalEXT(glx::Drawable drawable,int intervals) const428 void FunctionsGLX::swapIntervalEXT(glx::Drawable drawable, int intervals) const
429 {
430 mFnPtrs->swapIntervalEXTPtr(mXDisplay, drawable, intervals);
431 }
432
swapIntervalMESA(int intervals) const433 int FunctionsGLX::swapIntervalMESA(int intervals) const
434 {
435 return mFnPtrs->swapIntervalMESAPtr(intervals);
436 }
437
swapIntervalSGI(int intervals) const438 int FunctionsGLX::swapIntervalSGI(int intervals) const
439 {
440 return mFnPtrs->swapIntervalSGIPtr(intervals);
441 }
442
getSyncValuesOML(glx::Drawable drawable,int64_t * ust,int64_t * msc,int64_t * sbc) const443 bool FunctionsGLX::getSyncValuesOML(glx::Drawable drawable,
444 int64_t *ust,
445 int64_t *msc,
446 int64_t *sbc) const
447 {
448 return mFnPtrs->getSyncValuesOMLPtr(mXDisplay, drawable, ust, msc, sbc);
449 }
450
getMscRateOML(glx::Drawable drawable,int32_t * numerator,int32_t * denominator) const451 bool FunctionsGLX::getMscRateOML(glx::Drawable drawable,
452 int32_t *numerator,
453 int32_t *denominator) const
454 {
455 return mFnPtrs->getMscRateOMLPtr(mXDisplay, drawable, numerator, denominator);
456 }
457
bindTexImageEXT(glx::Drawable drawable,int buffer,const int * attribList) const458 void FunctionsGLX::bindTexImageEXT(glx::Drawable drawable, int buffer, const int *attribList) const
459 {
460 mFnPtrs->bindTexImageEXTPtr(mXDisplay, drawable, buffer, attribList);
461 }
releaseTexImageEXT(glx::Drawable drawable,int buffer) const462 void FunctionsGLX::releaseTexImageEXT(glx::Drawable drawable, int buffer) const
463 {
464 mFnPtrs->releaseTexImageEXTPtr(mXDisplay, drawable, buffer);
465 }
466 } // namespace rx
467