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 createContextAttribsARBPtr(nullptr),
60 swapIntervalEXTPtr(nullptr),
61 swapIntervalMESAPtr(nullptr),
62 swapIntervalSGIPtr(nullptr),
63 getSyncValuesOMLPtr(nullptr),
64 getMscRateOMLPtr(nullptr)
65 {}
66
67 // GLX 1.0
68 PFNGLXCREATECONTEXTPROC createContextPtr;
69 PFNGLXDESTROYCONTEXTPROC destroyContextPtr;
70 PFNGLXMAKECURRENTPROC makeCurrentPtr;
71 PFNGLXSWAPBUFFERSPROC swapBuffersPtr;
72 PFNGLXQUERYEXTENSIONPROC queryExtensionPtr;
73 PFNGLXQUERYVERSIONPROC queryVersionPtr;
74 PFNGLXGETCURRENTCONTEXTPROC getCurrentContextPtr;
75 PFNGLXGETCURRENTDRAWABLEPROC getCurrentDrawablePtr;
76 PFNGLXWAITXPROC waitXPtr;
77 PFNGLXWAITGLPROC waitGLPtr;
78
79 // GLX 1.1
80 PFNGLXGETCLIENTSTRINGPROC getClientStringPtr;
81 PFNGLXQUERYEXTENSIONSSTRINGPROC queryExtensionsStringPtr;
82
83 // GLX 1.3
84 PFNGLXGETFBCONFIGSPROC getFBConfigsPtr;
85 PFNGLXCHOOSEFBCONFIGPROC chooseFBConfigPtr;
86 PFNGLXGETFBCONFIGATTRIBPROC getFBConfigAttribPtr;
87 PFNGLXGETVISUALFROMFBCONFIGPROC getVisualFromFBConfigPtr;
88 PFNGLXCREATEWINDOWPROC createWindowPtr;
89 PFNGLXDESTROYWINDOWPROC destroyWindowPtr;
90 PFNGLXCREATEPBUFFERPROC createPbufferPtr;
91 PFNGLXDESTROYPBUFFERPROC destroyPbufferPtr;
92 PFNGLXQUERYDRAWABLEPROC queryDrawablePtr;
93
94 // GLX_ARB_create_context
95 PFNGLXCREATECONTEXTATTRIBSARBPROC createContextAttribsARBPtr;
96
97 // GLX_EXT_swap_control
98 PFNGLXSWAPINTERVALEXTPROC swapIntervalEXTPtr;
99
100 // GLX_MESA_swap_control
101 PFNGLXSWAPINTERVALMESAPROC swapIntervalMESAPtr;
102
103 // GLX_SGI_swap_control
104 PFNGLXSWAPINTERVALSGIPROC swapIntervalSGIPtr;
105
106 // GLX_OML_sync_control
107 PFNGLXGETSYNCVALUESOMLPROC getSyncValuesOMLPtr;
108 PFNGLXGETMSCRATEOMLPROC getMscRateOMLPtr;
109 };
110
FunctionsGLX()111 FunctionsGLX::FunctionsGLX()
112 : majorVersion(0),
113 minorVersion(0),
114 mXDisplay(nullptr),
115 mXScreen(-1),
116 mFnPtrs(new GLXFunctionTable())
117 {}
118
~FunctionsGLX()119 FunctionsGLX::~FunctionsGLX()
120 {
121 delete mFnPtrs;
122 terminate();
123 }
124
initialize(Display * xDisplay,int screen,std::string * errorString)125 bool FunctionsGLX::initialize(Display *xDisplay, int screen, std::string *errorString)
126 {
127 terminate();
128 mXDisplay = xDisplay;
129 mXScreen = screen;
130
131 #if !defined(ANGLE_LINK_GLX)
132 // Some OpenGL implementations can't handle having this library
133 // handle closed while there's any X window still open against
134 // which a GLXWindow was ever created.
135 if (!sLibHandle)
136 {
137 sLibHandle = dlopen("libGL.so.1", RTLD_NOW);
138 if (!sLibHandle)
139 {
140 *errorString = std::string("Could not dlopen libGL.so.1: ") + dlerror();
141 return false;
142 }
143 }
144
145 getProc = reinterpret_cast<PFNGETPROCPROC>(dlsym(sLibHandle, "glXGetProcAddress"));
146 if (!getProc)
147 {
148 getProc = reinterpret_cast<PFNGETPROCPROC>(dlsym(sLibHandle, "glXGetProcAddressARB"));
149 }
150 if (!getProc)
151 {
152 *errorString = "Could not retrieve glXGetProcAddress";
153 return false;
154 }
155 #else
156 getProc = reinterpret_cast<PFNGETPROCPROC>(glXGetProcAddress);
157 #endif
158
159 #define GET_PROC_OR_ERROR(MEMBER, NAME) \
160 do \
161 { \
162 if (!GetProc(getProc, MEMBER, #NAME)) \
163 { \
164 *errorString = "Could not load GLX entry point " #NAME; \
165 return false; \
166 } \
167 } while (0)
168 #if !defined(ANGLE_LINK_GLX)
169 # define GET_FNPTR_OR_ERROR(MEMBER, NAME) GET_PROC_OR_ERROR(MEMBER, NAME)
170 #else
171 # define GET_FNPTR_OR_ERROR(MEMBER, NAME) *MEMBER = NAME
172 #endif
173
174 // GLX 1.0
175 GET_FNPTR_OR_ERROR(&mFnPtrs->createContextPtr, glXCreateContext);
176 GET_FNPTR_OR_ERROR(&mFnPtrs->destroyContextPtr, glXDestroyContext);
177 GET_FNPTR_OR_ERROR(&mFnPtrs->makeCurrentPtr, glXMakeCurrent);
178 GET_FNPTR_OR_ERROR(&mFnPtrs->swapBuffersPtr, glXSwapBuffers);
179 GET_FNPTR_OR_ERROR(&mFnPtrs->queryExtensionPtr, glXQueryExtension);
180 GET_FNPTR_OR_ERROR(&mFnPtrs->queryVersionPtr, glXQueryVersion);
181 GET_FNPTR_OR_ERROR(&mFnPtrs->getCurrentContextPtr, glXGetCurrentContext);
182 GET_FNPTR_OR_ERROR(&mFnPtrs->getCurrentDrawablePtr, glXGetCurrentDrawable);
183 GET_FNPTR_OR_ERROR(&mFnPtrs->waitXPtr, glXWaitX);
184 GET_FNPTR_OR_ERROR(&mFnPtrs->waitGLPtr, glXWaitGL);
185
186 // GLX 1.1
187 GET_FNPTR_OR_ERROR(&mFnPtrs->getClientStringPtr, glXGetClientString);
188 GET_FNPTR_OR_ERROR(&mFnPtrs->queryExtensionsStringPtr, glXQueryExtensionsString);
189
190 // Check we have a working GLX
191 {
192 int errorBase;
193 int eventBase;
194 if (!queryExtension(&errorBase, &eventBase))
195 {
196 *errorString = "GLX is not present.";
197 return false;
198 }
199 }
200
201 // Check we have a supported version of GLX
202 if (!queryVersion(&majorVersion, &minorVersion))
203 {
204 *errorString = "Could not query the GLX version.";
205 return false;
206 }
207 if (majorVersion != 1 || minorVersion < 3)
208 {
209 *errorString = "Unsupported GLX version (requires at least 1.3).";
210 return false;
211 }
212
213 const char *extensions = queryExtensionsString();
214 if (!extensions)
215 {
216 *errorString = "glXQueryExtensionsString returned NULL";
217 return false;
218 }
219 angle::SplitStringAlongWhitespace(extensions, &mExtensions);
220
221 // GLX 1.3
222 GET_FNPTR_OR_ERROR(&mFnPtrs->getFBConfigsPtr, glXGetFBConfigs);
223 GET_FNPTR_OR_ERROR(&mFnPtrs->chooseFBConfigPtr, glXChooseFBConfig);
224 GET_FNPTR_OR_ERROR(&mFnPtrs->getFBConfigAttribPtr, glXGetFBConfigAttrib);
225 GET_FNPTR_OR_ERROR(&mFnPtrs->getVisualFromFBConfigPtr, glXGetVisualFromFBConfig);
226 GET_FNPTR_OR_ERROR(&mFnPtrs->createWindowPtr, glXCreateWindow);
227 GET_FNPTR_OR_ERROR(&mFnPtrs->destroyWindowPtr, glXDestroyWindow);
228 GET_FNPTR_OR_ERROR(&mFnPtrs->createPbufferPtr, glXCreatePbuffer);
229 GET_FNPTR_OR_ERROR(&mFnPtrs->destroyPbufferPtr, glXDestroyPbuffer);
230 GET_FNPTR_OR_ERROR(&mFnPtrs->queryDrawablePtr, glXQueryDrawable);
231
232 // Extensions
233 if (hasExtension("GLX_ARB_create_context"))
234 {
235 GET_PROC_OR_ERROR(&mFnPtrs->createContextAttribsARBPtr, glXCreateContextAttribsARB);
236 }
237 if (hasExtension("GLX_EXT_swap_control"))
238 {
239 GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalEXTPtr, glXSwapIntervalEXT);
240 }
241 if (hasExtension("GLX_MESA_swap_control"))
242 {
243 GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalMESAPtr, glXSwapIntervalMESA);
244 }
245 if (hasExtension("GLX_SGI_swap_control"))
246 {
247 GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalSGIPtr, glXSwapIntervalSGI);
248 }
249 if (hasExtension("GLX_OML_sync_control"))
250 {
251 GET_PROC_OR_ERROR(&mFnPtrs->getSyncValuesOMLPtr, glXGetSyncValuesOML);
252 GET_PROC_OR_ERROR(&mFnPtrs->getMscRateOMLPtr, glXGetMscRateOML);
253 }
254
255 #undef GET_FNPTR_OR_ERROR
256 #undef GET_PROC_OR_ERROR
257
258 *errorString = "";
259 return true;
260 }
261
terminate()262 void FunctionsGLX::terminate() {}
263
hasExtension(const char * extension) const264 bool FunctionsGLX::hasExtension(const char *extension) const
265 {
266 return std::find(mExtensions.begin(), mExtensions.end(), extension) != mExtensions.end();
267 }
268
getDisplay() const269 Display *FunctionsGLX::getDisplay() const
270 {
271 return mXDisplay;
272 }
273
getScreen() const274 int FunctionsGLX::getScreen() const
275 {
276 return mXScreen;
277 }
278
279 // GLX functions
280
281 // GLX 1.0
createContext(XVisualInfo * visual,glx::Context share,bool direct) const282 glx::Context FunctionsGLX::createContext(XVisualInfo *visual, glx::Context share, bool direct) const
283 {
284 GLXContext shareCtx = reinterpret_cast<GLXContext>(share);
285 GLXContext context = mFnPtrs->createContextPtr(mXDisplay, visual, shareCtx, direct);
286 return reinterpret_cast<glx::Context>(context);
287 }
destroyContext(glx::Context context) const288 void FunctionsGLX::destroyContext(glx::Context context) const
289 {
290 GLXContext ctx = reinterpret_cast<GLXContext>(context);
291 mFnPtrs->destroyContextPtr(mXDisplay, ctx);
292 }
makeCurrent(glx::Drawable drawable,glx::Context context) const293 Bool FunctionsGLX::makeCurrent(glx::Drawable drawable, glx::Context context) const
294 {
295 GLXContext ctx = reinterpret_cast<GLXContext>(context);
296 return mFnPtrs->makeCurrentPtr(mXDisplay, drawable, ctx);
297 }
swapBuffers(glx::Drawable drawable) const298 void FunctionsGLX::swapBuffers(glx::Drawable drawable) const
299 {
300 mFnPtrs->swapBuffersPtr(mXDisplay, drawable);
301 }
queryExtension(int * errorBase,int * event) const302 Bool FunctionsGLX::queryExtension(int *errorBase, int *event) const
303 {
304 return mFnPtrs->queryExtensionPtr(mXDisplay, errorBase, event);
305 }
queryVersion(int * major,int * minor) const306 Bool FunctionsGLX::queryVersion(int *major, int *minor) const
307 {
308 return mFnPtrs->queryVersionPtr(mXDisplay, major, minor);
309 }
getCurrentContext() const310 glx::Context FunctionsGLX::getCurrentContext() const
311 {
312 GLXContext context = mFnPtrs->getCurrentContextPtr();
313 return reinterpret_cast<glx::Context>(context);
314 }
getCurrentDrawable() const315 glx::Drawable FunctionsGLX::getCurrentDrawable() const
316 {
317 GLXDrawable drawable = mFnPtrs->getCurrentDrawablePtr();
318 return reinterpret_cast<glx::Drawable>(drawable);
319 }
waitX() const320 void FunctionsGLX::waitX() const
321 {
322 mFnPtrs->waitXPtr();
323 }
waitGL() const324 void FunctionsGLX::waitGL() const
325 {
326 mFnPtrs->waitGLPtr();
327 }
328
329 // GLX 1.1
getClientString(int name) const330 const char *FunctionsGLX::getClientString(int name) const
331 {
332 return mFnPtrs->getClientStringPtr(mXDisplay, name);
333 }
334
queryExtensionsString() const335 const char *FunctionsGLX::queryExtensionsString() const
336 {
337 return mFnPtrs->queryExtensionsStringPtr(mXDisplay, mXScreen);
338 }
339
340 // GLX 1.4
getFBConfigs(int * nElements) const341 glx::FBConfig *FunctionsGLX::getFBConfigs(int *nElements) const
342 {
343 GLXFBConfig *configs = mFnPtrs->getFBConfigsPtr(mXDisplay, mXScreen, nElements);
344 return reinterpret_cast<glx::FBConfig *>(configs);
345 }
chooseFBConfig(const int * attribList,int * nElements) const346 glx::FBConfig *FunctionsGLX::chooseFBConfig(const int *attribList, int *nElements) const
347 {
348 GLXFBConfig *configs = mFnPtrs->chooseFBConfigPtr(mXDisplay, mXScreen, attribList, nElements);
349 return reinterpret_cast<glx::FBConfig *>(configs);
350 }
getFBConfigAttrib(glx::FBConfig config,int attribute,int * value) const351 int FunctionsGLX::getFBConfigAttrib(glx::FBConfig config, int attribute, int *value) const
352 {
353 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
354 return mFnPtrs->getFBConfigAttribPtr(mXDisplay, cfg, attribute, value);
355 }
getVisualFromFBConfig(glx::FBConfig config) const356 XVisualInfo *FunctionsGLX::getVisualFromFBConfig(glx::FBConfig config) const
357 {
358 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
359 return mFnPtrs->getVisualFromFBConfigPtr(mXDisplay, cfg);
360 }
createWindow(glx::FBConfig config,Window window,const int * attribList) const361 GLXWindow FunctionsGLX::createWindow(glx::FBConfig config,
362 Window window,
363 const int *attribList) const
364 {
365 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
366 return mFnPtrs->createWindowPtr(mXDisplay, cfg, window, attribList);
367 }
destroyWindow(glx::Window window) const368 void FunctionsGLX::destroyWindow(glx::Window window) const
369 {
370 mFnPtrs->destroyWindowPtr(mXDisplay, window);
371 }
createPbuffer(glx::FBConfig config,const int * attribList) const372 glx::Pbuffer FunctionsGLX::createPbuffer(glx::FBConfig config, const int *attribList) const
373 {
374 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
375 return mFnPtrs->createPbufferPtr(mXDisplay, cfg, attribList);
376 }
destroyPbuffer(glx::Pbuffer pbuffer) const377 void FunctionsGLX::destroyPbuffer(glx::Pbuffer pbuffer) const
378 {
379 mFnPtrs->destroyPbufferPtr(mXDisplay, pbuffer);
380 }
queryDrawable(glx::Drawable drawable,int attribute,unsigned int * value) const381 void FunctionsGLX::queryDrawable(glx::Drawable drawable, int attribute, unsigned int *value) const
382 {
383 mFnPtrs->queryDrawablePtr(mXDisplay, drawable, attribute, value);
384 }
385
386 // GLX_ARB_create_context
createContextAttribsARB(glx::FBConfig config,glx::Context shareContext,Bool direct,const int * attribList) const387 glx::Context FunctionsGLX::createContextAttribsARB(glx::FBConfig config,
388 glx::Context shareContext,
389 Bool direct,
390 const int *attribList) const
391 {
392 GLXContext shareCtx = reinterpret_cast<GLXContext>(shareContext);
393 GLXFBConfig cfg = reinterpret_cast<GLXFBConfig>(config);
394 GLXContext ctx =
395 mFnPtrs->createContextAttribsARBPtr(mXDisplay, cfg, shareCtx, direct, attribList);
396 return reinterpret_cast<glx::Context>(ctx);
397 }
398
swapIntervalEXT(glx::Drawable drawable,int intervals) const399 void FunctionsGLX::swapIntervalEXT(glx::Drawable drawable, int intervals) const
400 {
401 mFnPtrs->swapIntervalEXTPtr(mXDisplay, drawable, intervals);
402 }
403
swapIntervalMESA(int intervals) const404 int FunctionsGLX::swapIntervalMESA(int intervals) const
405 {
406 return mFnPtrs->swapIntervalMESAPtr(intervals);
407 }
408
swapIntervalSGI(int intervals) const409 int FunctionsGLX::swapIntervalSGI(int intervals) const
410 {
411 return mFnPtrs->swapIntervalSGIPtr(intervals);
412 }
413
getSyncValuesOML(glx::Drawable drawable,int64_t * ust,int64_t * msc,int64_t * sbc) const414 bool FunctionsGLX::getSyncValuesOML(glx::Drawable drawable,
415 int64_t *ust,
416 int64_t *msc,
417 int64_t *sbc) const
418 {
419 return mFnPtrs->getSyncValuesOMLPtr(mXDisplay, drawable, ust, msc, sbc);
420 }
421
getMscRateOML(glx::Drawable drawable,int32_t * numerator,int32_t * denominator) const422 bool FunctionsGLX::getMscRateOML(glx::Drawable drawable,
423 int32_t *numerator,
424 int32_t *denominator) const
425 {
426 return mFnPtrs->getMscRateOMLPtr(mXDisplay, drawable, numerator, denominator);
427 }
428
429 } // namespace rx
430