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