]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CGLXManager.cpp
Add a unified cross platform OpenGL core profile binding (#52)
[irrlicht.git] / source / Irrlicht / CGLXManager.cpp
1 // Copyright (C) 2013 Christian Stehno\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in Irrlicht.h\r
4 \r
5 #include "CGLXManager.h"\r
6 \r
7 #ifdef _IRR_COMPILE_WITH_GLX_MANAGER_\r
8 \r
9 #include "os.h"\r
10 #include <dlfcn.h>\r
11 \r
12 #if defined(_IRR_OPENGL_USE_EXTPOINTER_)\r
13         #define GL_GLEXT_LEGACY 1\r
14         #define GLX_GLXEXT_LEGACY 1\r
15 #else\r
16         #define GL_GLEXT_PROTOTYPES 1\r
17         #define GLX_GLXEXT_PROTOTYPES 1\r
18 #endif\r
19 #include <GL/gl.h>\r
20 #include <GL/glx.h>\r
21 #if defined(_IRR_OPENGL_USE_EXTPOINTER_)\r
22 #include <GL/glext.h>\r
23 #include <GL/glxext.h>\r
24 #endif\r
25 \r
26 namespace irr\r
27 {\r
28 namespace video\r
29 {\r
30 \r
31 CGLXManager::CGLXManager(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata, int screennr)\r
32         : Params(params), PrimaryContext(videodata), VisualInfo(0), glxFBConfig(0), GlxWin(0), libHandle(NULL)\r
33 {\r
34         #ifdef _DEBUG\r
35         setDebugName("CGLXManager");\r
36         #endif\r
37 \r
38         CurrentContext.OpenGLLinux.X11Display=PrimaryContext.OpenGLLinux.X11Display;\r
39 \r
40         int major, minor;\r
41         Display* display = (Display*)PrimaryContext.OpenGLLinux.X11Display;\r
42         const bool isAvailableGLX=glXQueryExtension(display,&major,&minor);\r
43 \r
44         if (isAvailableGLX && glXQueryVersion(display, &major, &minor))\r
45         {\r
46 #if defined(GLX_VERSION_1_3)\r
47                 typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);\r
48 \r
49 #ifdef _IRR_OPENGL_USE_EXTPOINTER_\r
50                 PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXChooseFBConfig"));\r
51 #else\r
52                 PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig=glXChooseFBConfig;\r
53 #endif\r
54                 if (major==1 && minor>2 && glxChooseFBConfig)\r
55                 {\r
56 os::Printer::log("GLX >= 1.3", ELL_DEBUG);\r
57                         // attribute array for the draw buffer\r
58                         int visualAttrBuffer[] =\r
59                         {\r
60                                 GLX_RENDER_TYPE, GLX_RGBA_BIT,\r
61                                 GLX_RED_SIZE, 4,\r
62                                 GLX_GREEN_SIZE, 4,\r
63                                 GLX_BLUE_SIZE, 4,\r
64                                 GLX_ALPHA_SIZE, Params.WithAlphaChannel?1:0,\r
65                                 GLX_DEPTH_SIZE, Params.ZBufferBits, //10,11\r
66                                 GLX_DOUBLEBUFFER, Params.Doublebuffer?True:False,\r
67                                 GLX_STENCIL_SIZE, Params.Stencilbuffer?1:0,\r
68 #if defined(GLX_VERSION_1_4) && defined(GLX_SAMPLE_BUFFERS) // we need to check the extension string!\r
69                                 GLX_SAMPLE_BUFFERS, 1,\r
70                                 GLX_SAMPLES, Params.AntiAlias, // 18,19\r
71 #elif defined(GLX_ARB_multisample)\r
72                                 GLX_SAMPLE_BUFFERS_ARB, 1,\r
73                                 GLX_SAMPLES_ARB, Params.AntiAlias, // 18,19\r
74 #elif defined(GLX_SGIS_multisample)\r
75                                 GLX_SAMPLE_BUFFERS_SGIS, 1,\r
76                                 GLX_SAMPLES_SGIS, Params.AntiAlias, // 18,19\r
77 #endif\r
78 //#ifdef GL_ARB_framebuffer_sRGB\r
79 //                                      GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB,\r
80 //#elif defined(GL_EXT_framebuffer_sRGB)\r
81 //                                      GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, Params.HandleSRGB,\r
82 //#endif\r
83                                 GLX_STEREO, Params.Stereobuffer?True:False,\r
84                                 None\r
85                         };\r
86 \r
87                         GLXFBConfig *configList=0;\r
88                         int nitems=0;\r
89                         if (Params.AntiAlias<2)\r
90                         {\r
91                                 visualAttrBuffer[17] = 0;\r
92                                 visualAttrBuffer[19] = 0;\r
93                         }\r
94                         // first round with unchanged values\r
95                         {\r
96                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
97                                 if (!configList && Params.AntiAlias)\r
98                                 {\r
99                                         while (!configList && (visualAttrBuffer[19]>1))\r
100                                         {\r
101                                                 visualAttrBuffer[19] -= 1;\r
102                                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
103                                         }\r
104                                         if (!configList)\r
105                                         {\r
106                                                 visualAttrBuffer[17] = 0;\r
107                                                 visualAttrBuffer[19] = 0;\r
108                                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
109                                                 if (configList)\r
110                                                 {\r
111                                                         os::Printer::log("No FSAA available.", ELL_WARNING);\r
112                                                         Params.AntiAlias=0;\r
113                                                 }\r
114                                                 else\r
115                                                 {\r
116                                                         //reenable multisampling\r
117                                                         visualAttrBuffer[17] = 1;\r
118                                                         visualAttrBuffer[19] = Params.AntiAlias;\r
119                                                 }\r
120                                         }\r
121                                 }\r
122                         }\r
123                         // Next try with flipped stencil buffer value\r
124                         // If the first round was with stencil flag it's now without\r
125                         // Other way round also makes sense because some configs\r
126                         // only have depth buffer combined with stencil buffer\r
127                         if (!configList)\r
128                         {\r
129                                 if (Params.Stencilbuffer)\r
130                                         os::Printer::log("No stencilbuffer available, disabling stencil shadows.", ELL_WARNING);\r
131                                 Params.Stencilbuffer = !Params.Stencilbuffer;\r
132                                 visualAttrBuffer[15]=Params.Stencilbuffer?1:0;\r
133 \r
134                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
135                                 if (!configList && Params.AntiAlias)\r
136                                 {\r
137                                         while (!configList && (visualAttrBuffer[19]>1))\r
138                                         {\r
139                                                 visualAttrBuffer[19] -= 1;\r
140                                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
141                                         }\r
142                                         if (!configList)\r
143                                         {\r
144                                                 visualAttrBuffer[17] = 0;\r
145                                                 visualAttrBuffer[19] = 0;\r
146                                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
147                                                 if (configList)\r
148                                                 {\r
149                                                         os::Printer::log("No FSAA available.", ELL_WARNING);\r
150                                                         Params.AntiAlias=0;\r
151                                                 }\r
152                                                 else\r
153                                                 {\r
154                                                         //reenable multisampling\r
155                                                         visualAttrBuffer[17] = 1;\r
156                                                         visualAttrBuffer[19] = Params.AntiAlias;\r
157                                                 }\r
158                                         }\r
159                                 }\r
160                         }\r
161                         // Next try without double buffer\r
162                         if (!configList && Params.Doublebuffer)\r
163                         {\r
164                                 os::Printer::log("No doublebuffering available.", ELL_WARNING);\r
165                                 Params.Doublebuffer=false;\r
166                                 visualAttrBuffer[13] = GLX_DONT_CARE;\r
167                                 Params.Stencilbuffer = false;\r
168                                 visualAttrBuffer[15]=0;\r
169                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
170                                 if (!configList && Params.AntiAlias)\r
171                                 {\r
172                                         while (!configList && (visualAttrBuffer[19]>1))\r
173                                         {\r
174                                                 visualAttrBuffer[19] -= 1;\r
175                                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
176                                         }\r
177                                         if (!configList)\r
178                                         {\r
179                                                 visualAttrBuffer[17] = 0;\r
180                                                 visualAttrBuffer[19] = 0;\r
181                                                 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);\r
182                                                 if (configList)\r
183                                                 {\r
184                                                         os::Printer::log("No FSAA available.", ELL_WARNING);\r
185                                                         Params.AntiAlias=0;\r
186                                                 }\r
187                                                 else\r
188                                                 {\r
189                                                         //reenable multisampling\r
190                                                         visualAttrBuffer[17] = 1;\r
191                                                         visualAttrBuffer[19] = Params.AntiAlias;\r
192                                                 }\r
193                                         }\r
194                                 }\r
195                         }\r
196                         if (configList)\r
197                         {\r
198                                 glxFBConfig=configList[0];\r
199                                 XFree(configList);\r
200 #ifdef _IRR_OPENGL_USE_EXTPOINTER_\r
201                                 typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);\r
202                                 PFNGLXGETVISUALFROMFBCONFIGPROC glxGetVisualFromFBConfig= (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXGetVisualFromFBConfig"));\r
203                                 if (glxGetVisualFromFBConfig)\r
204                                         VisualInfo = glxGetVisualFromFBConfig(display,(GLXFBConfig)glxFBConfig);\r
205 #else\r
206                                         VisualInfo = glXGetVisualFromFBConfig(display,(GLXFBConfig)glxFBConfig);\r
207 #endif\r
208                         }\r
209                 }\r
210                 else\r
211 #endif\r
212                 {\r
213                         // attribute array for the draw buffer\r
214                         int visualAttrBuffer[] =\r
215                         {\r
216                                 GLX_RGBA, GLX_USE_GL,\r
217                                 GLX_RED_SIZE, 4,\r
218                                 GLX_GREEN_SIZE, 4,\r
219                                 GLX_BLUE_SIZE, 4,\r
220                                 GLX_ALPHA_SIZE, Params.WithAlphaChannel?1:0,\r
221                                 GLX_DEPTH_SIZE, Params.ZBufferBits,\r
222                                 GLX_STENCIL_SIZE, Params.Stencilbuffer?1:0, // 12,13\r
223                                 // The following attributes have no flags, but are\r
224                                 // either present or not. As a no-op we use\r
225                                 // GLX_USE_GL, which is silently ignored by glXChooseVisual\r
226                                 Params.Doublebuffer?GLX_DOUBLEBUFFER:GLX_USE_GL, // 14\r
227                                 Params.Stereobuffer?GLX_STEREO:GLX_USE_GL, // 15\r
228 //#ifdef GL_ARB_framebuffer_sRGB\r
229 //                                      Params.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB:GLX_USE_GL,\r
230 //#elif defined(GL_EXT_framebuffer_sRGB)\r
231 //                                      Params.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT:GLX_USE_GL,\r
232 //#endif\r
233                                 None\r
234                         };\r
235 \r
236                         VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer);\r
237                         if (!VisualInfo)\r
238                         {\r
239                                 if (Params.Stencilbuffer)\r
240                                         os::Printer::log("No stencilbuffer available, disabling.", ELL_WARNING);\r
241                                 Params.Stencilbuffer = !Params.Stencilbuffer;\r
242                                 visualAttrBuffer[13]=Params.Stencilbuffer?1:0;\r
243 \r
244                                 VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer);\r
245                                 if (!VisualInfo && Params.Doublebuffer)\r
246                                 {\r
247                                         os::Printer::log("No doublebuffering available.", ELL_WARNING);\r
248                                         Params.Doublebuffer=false;\r
249                                         visualAttrBuffer[14] = GLX_USE_GL;\r
250                                         VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer);\r
251                                 }\r
252                         }\r
253                 }\r
254         }\r
255         else\r
256                 os::Printer::log("No GLX support available. OpenGL driver will not work.", ELL_WARNING);\r
257 }\r
258 \r
259 CGLXManager::~CGLXManager()\r
260 {\r
261 }\r
262 \r
263 bool CGLXManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata)\r
264 {\r
265         // store params\r
266         Params=params;\r
267 \r
268         // set display\r
269         CurrentContext.OpenGLLinux.X11Display=videodata.OpenGLLinux.X11Display;\r
270 \r
271         // now get new window\r
272         CurrentContext.OpenGLLinux.X11Window=videodata.OpenGLLinux.X11Window;\r
273         if (!PrimaryContext.OpenGLLinux.X11Window)\r
274         {\r
275                 PrimaryContext.OpenGLLinux.X11Window=CurrentContext.OpenGLLinux.X11Window;\r
276         }\r
277 \r
278         return true;\r
279 }\r
280 \r
281 void CGLXManager::terminate()\r
282 {\r
283         if (libHandle)\r
284                 dlclose(libHandle);\r
285         memset(&CurrentContext, 0, sizeof(CurrentContext));\r
286 }\r
287 \r
288 bool CGLXManager::generateSurface()\r
289 {\r
290         if (glxFBConfig)\r
291         {\r
292                 GlxWin=glXCreateWindow((Display*)CurrentContext.OpenGLLinux.X11Display,(GLXFBConfig)glxFBConfig,CurrentContext.OpenGLLinux.X11Window,NULL);\r
293                 if (!GlxWin)\r
294                 {\r
295                         os::Printer::log("Could not create GLX window.", ELL_WARNING);\r
296                         return false;\r
297                 }\r
298 \r
299                 CurrentContext.OpenGLLinux.GLXWindow=GlxWin;\r
300         }\r
301         else\r
302         {\r
303                 CurrentContext.OpenGLLinux.GLXWindow=CurrentContext.OpenGLLinux.X11Window;\r
304         }\r
305         return true;\r
306 }\r
307 \r
308 void CGLXManager::destroySurface()\r
309 {\r
310         if (GlxWin)\r
311                 glXDestroyWindow((Display*)CurrentContext.OpenGLLinux.X11Display, GlxWin);\r
312 }\r
313 \r
314 bool CGLXManager::generateContext()\r
315 {\r
316         GLXContext context;\r
317 \r
318         if (glxFBConfig)\r
319         {\r
320                 if (GlxWin)\r
321                 {\r
322                         // create glx context\r
323                         context = glXCreateNewContext((Display*)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, GLX_RGBA_TYPE, NULL, True);\r
324                         if (!context)\r
325                         {\r
326                                 os::Printer::log("Could not create GLX rendering context.", ELL_WARNING);\r
327                                 return false;\r
328                         }\r
329                 }\r
330                 else\r
331                 {\r
332                         os::Printer::log("GLX window was not properly created.", ELL_WARNING);\r
333                         return false;\r
334                 }\r
335         }\r
336         else\r
337         {\r
338                 context = glXCreateContext((Display*)CurrentContext.OpenGLLinux.X11Display, VisualInfo, NULL, True);\r
339                 if (!context)\r
340                 {\r
341                         os::Printer::log("Could not create GLX rendering context.", ELL_WARNING);\r
342                         return false;\r
343                 }\r
344         }\r
345         CurrentContext.OpenGLLinux.X11Context=context;\r
346         return true;\r
347 }\r
348 \r
349 const SExposedVideoData& CGLXManager::getContext() const\r
350 {\r
351         return CurrentContext;\r
352 }\r
353 \r
354 bool CGLXManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero)\r
355 {\r
356         //TODO: handle restorePrimaryOnZero\r
357 \r
358         if (videoData.OpenGLLinux.X11Window)\r
359         {\r
360                 if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context)\r
361                 {\r
362                         if (!glXMakeCurrent((Display*)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.GLXWindow, (GLXContext)videoData.OpenGLLinux.X11Context))\r
363                         {\r
364                                 os::Printer::log("Context activation failed.");\r
365                                 return false;\r
366                         }\r
367                         else\r
368                         {\r
369                                 CurrentContext.OpenGLLinux.GLXWindow = videoData.OpenGLLinux.GLXWindow;\r
370                                 CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window;\r
371                                 CurrentContext.OpenGLLinux.X11Display = videoData.OpenGLLinux.X11Display;\r
372                         }\r
373                 }\r
374                 else\r
375                 {\r
376                         // in case we only got a window ID, try with the existing values for display and context\r
377                         if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, videoData.OpenGLLinux.GLXWindow, (GLXContext)PrimaryContext.OpenGLLinux.X11Context))\r
378                         {\r
379                                 os::Printer::log("Context activation failed.");\r
380                                 return false;\r
381                         }\r
382                         else\r
383                         {\r
384                                 CurrentContext.OpenGLLinux.GLXWindow = videoData.OpenGLLinux.GLXWindow;\r
385                                 CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window;\r
386                                 CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display;\r
387                         }\r
388                 }\r
389         }\r
390         else if (!restorePrimaryOnZero && !videoData.OpenGLLinux.X11Window && !videoData.OpenGLLinux.X11Display)\r
391         {\r
392                 if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, None, NULL))\r
393                 {\r
394                         os::Printer::log("Render Context reset failed.");\r
395                         return false;\r
396                 }\r
397                 CurrentContext.OpenGLLinux.X11Window = 0;\r
398                 CurrentContext.OpenGLLinux.X11Display = 0;\r
399         }\r
400         // set back to main context\r
401         else if (CurrentContext.OpenGLLinux.X11Display != PrimaryContext.OpenGLLinux.X11Display)\r
402         {\r
403                 if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, PrimaryContext.OpenGLLinux.X11Window, (GLXContext)PrimaryContext.OpenGLLinux.X11Context))\r
404                 {\r
405                         os::Printer::log("Context activation failed.");\r
406                         return false;\r
407                 }\r
408                 else\r
409                 {\r
410                         CurrentContext = PrimaryContext;\r
411                 }\r
412         }\r
413         return true;\r
414 }\r
415 \r
416 void CGLXManager::destroyContext()\r
417 {\r
418         if (CurrentContext.OpenGLLinux.X11Context)\r
419         {\r
420                 if (GlxWin)\r
421                 {\r
422                         if (!glXMakeContextCurrent((Display*)CurrentContext.OpenGLLinux.X11Display, None, None, NULL))\r
423                                 os::Printer::log("Could not release glx context.", ELL_WARNING);\r
424                 }\r
425                 else\r
426                 {\r
427                         if (!glXMakeCurrent((Display*)CurrentContext.OpenGLLinux.X11Display, None, NULL))\r
428                                 os::Printer::log("Could not release glx context.", ELL_WARNING);\r
429                 }\r
430                 glXDestroyContext((Display*)CurrentContext.OpenGLLinux.X11Display, (GLXContext)CurrentContext.OpenGLLinux.X11Context);\r
431         }\r
432 }\r
433 \r
434 void* CGLXManager::getProcAddress(const std::string &procName)\r
435 {\r
436         void* proc = NULL;\r
437         proc = (void*)glXGetProcAddressARB(reinterpret_cast<const GLubyte*>(procName.c_str()));\r
438         if (!proc) {\r
439                 if (!libHandle)\r
440                         libHandle = dlopen("libGL.so", RTLD_LAZY);\r
441                 if (libHandle)\r
442                         proc = dlsym(libHandle, procName.c_str());\r
443         }\r
444         return proc;\r
445 }\r
446 \r
447 bool CGLXManager::swapBuffers()\r
448 {\r
449         glXSwapBuffers((Display*)CurrentContext.OpenGLLinux.X11Display, CurrentContext.OpenGLLinux.GLXWindow);\r
450         return true;\r
451 }\r
452 \r
453 }\r
454 }\r
455 \r
456 #endif\r
457 \r