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
5 #include "CGLXManager.h"
\r
7 #ifdef _IRR_COMPILE_WITH_GLX_MANAGER_
\r
11 #if defined(_IRR_OPENGL_USE_EXTPOINTER_)
\r
12 #define GL_GLEXT_LEGACY 1
\r
13 #define GLX_GLXEXT_LEGACY 1
\r
15 #define GL_GLEXT_PROTOTYPES 1
\r
16 #define GLX_GLXEXT_PROTOTYPES 1
\r
20 #if defined(_IRR_OPENGL_USE_EXTPOINTER_)
\r
21 #include <GL/glext.h>
\r
22 #include <GL/glxext.h>
\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
34 setDebugName("CGLXManager");
\r
37 CurrentContext.OpenGLLinux.X11Display=PrimaryContext.OpenGLLinux.X11Display;
\r
40 Display* display = (Display*)PrimaryContext.OpenGLLinux.X11Display;
\r
41 const bool isAvailableGLX=glXQueryExtension(display,&major,&minor);
\r
43 if (isAvailableGLX && glXQueryVersion(display, &major, &minor))
\r
45 #if defined(GLX_VERSION_1_3)
\r
46 typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
\r
48 #ifdef _IRR_OPENGL_USE_EXTPOINTER_
\r
49 PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXChooseFBConfig"));
\r
51 PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig=glXChooseFBConfig;
\r
53 if (major==1 && minor>2 && glxChooseFBConfig)
\r
55 os::Printer::log("GLX >= 1.3", ELL_DEBUG);
\r
56 // attribute array for the draw buffer
\r
57 int visualAttrBuffer[] =
\r
59 GLX_RENDER_TYPE, GLX_RGBA_BIT,
\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
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
82 GLX_STEREO, Params.Stereobuffer?True:False,
\r
86 GLXFBConfig *configList=0;
\r
88 if (Params.AntiAlias<2)
\r
90 visualAttrBuffer[17] = 0;
\r
91 visualAttrBuffer[19] = 0;
\r
93 // first round with unchanged values
\r
95 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
\r
96 if (!configList && Params.AntiAlias)
\r
98 while (!configList && (visualAttrBuffer[19]>1))
\r
100 visualAttrBuffer[19] -= 1;
\r
101 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
\r
105 visualAttrBuffer[17] = 0;
\r
106 visualAttrBuffer[19] = 0;
\r
107 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
\r
110 os::Printer::log("No FSAA available.", ELL_WARNING);
\r
111 Params.AntiAlias=0;
\r
115 //reenable multisampling
\r
116 visualAttrBuffer[17] = 1;
\r
117 visualAttrBuffer[19] = Params.AntiAlias;
\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
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
133 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
\r
134 if (!configList && Params.AntiAlias)
\r
136 while (!configList && (visualAttrBuffer[19]>1))
\r
138 visualAttrBuffer[19] -= 1;
\r
139 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
\r
143 visualAttrBuffer[17] = 0;
\r
144 visualAttrBuffer[19] = 0;
\r
145 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
\r
148 os::Printer::log("No FSAA available.", ELL_WARNING);
\r
149 Params.AntiAlias=0;
\r
153 //reenable multisampling
\r
154 visualAttrBuffer[17] = 1;
\r
155 visualAttrBuffer[19] = Params.AntiAlias;
\r
160 // Next try without double buffer
\r
161 if (!configList && Params.Doublebuffer)
\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
171 while (!configList && (visualAttrBuffer[19]>1))
\r
173 visualAttrBuffer[19] -= 1;
\r
174 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
\r
178 visualAttrBuffer[17] = 0;
\r
179 visualAttrBuffer[19] = 0;
\r
180 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
\r
183 os::Printer::log("No FSAA available.", ELL_WARNING);
\r
184 Params.AntiAlias=0;
\r
188 //reenable multisampling
\r
189 visualAttrBuffer[17] = 1;
\r
190 visualAttrBuffer[19] = Params.AntiAlias;
\r
197 glxFBConfig=configList[0];
\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
205 VisualInfo = glXGetVisualFromFBConfig(display,(GLXFBConfig)glxFBConfig);
\r
212 // attribute array for the draw buffer
\r
213 int visualAttrBuffer[] =
\r
215 GLX_RGBA, GLX_USE_GL,
\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
235 VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer);
\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
243 VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer);
\r
244 if (!VisualInfo && Params.Doublebuffer)
\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
255 os::Printer::log("No GLX support available. OpenGL driver will not work.", ELL_WARNING);
\r
258 CGLXManager::~CGLXManager()
\r
262 bool CGLXManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata)
\r
268 CurrentContext.OpenGLLinux.X11Display=videodata.OpenGLLinux.X11Display;
\r
270 // now get new window
\r
271 CurrentContext.OpenGLLinux.X11Window=videodata.OpenGLLinux.X11Window;
\r
272 if (!PrimaryContext.OpenGLLinux.X11Window)
\r
274 PrimaryContext.OpenGLLinux.X11Window=CurrentContext.OpenGLLinux.X11Window;
\r
280 void CGLXManager::terminate()
\r
282 memset((void*)&CurrentContext, 0, sizeof(CurrentContext));
\r
285 bool CGLXManager::generateSurface()
\r
289 GlxWin=glXCreateWindow((Display*)CurrentContext.OpenGLLinux.X11Display,(GLXFBConfig)glxFBConfig,CurrentContext.OpenGLLinux.X11Window,NULL);
\r
292 os::Printer::log("Could not create GLX window.", ELL_WARNING);
\r
296 CurrentContext.OpenGLLinux.GLXWindow=GlxWin;
\r
300 CurrentContext.OpenGLLinux.GLXWindow=CurrentContext.OpenGLLinux.X11Window;
\r
305 void CGLXManager::destroySurface()
\r
308 glXDestroyWindow((Display*)CurrentContext.OpenGLLinux.X11Display, GlxWin);
\r
311 #if defined(GLX_ARB_create_context)
\r
312 static int IrrIgnoreError(Display *display, XErrorEvent *event)
\r
315 XGetErrorText(display, event->error_code, msg, 256);
\r
316 os::Printer::log("Ignoring an X error", msg, ELL_DEBUG);
\r
321 bool CGLXManager::generateContext()
\r
323 GLXContext context = 0;
\r
329 #if defined(GLX_ARB_create_context)
\r
331 #ifdef _IRR_OPENGL_USE_EXTPOINTER_
\r
332 PFNGLXCREATECONTEXTATTRIBSARBPROC glxCreateContextAttribsARB=(PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB"));
\r
334 PFNGLXCREATECONTEXTATTRIBSARBPROC glxCreateContextAttribsARB=glXCreateContextAttribsARB;
\r
337 if (glxCreateContextAttribsARB)
\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
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
354 // create glx context
\r
355 context = glXCreateNewContext((Display*)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, GLX_RGBA_TYPE, NULL, True);
\r
358 os::Printer::log("Could not create GLX rendering context.", ELL_WARNING);
\r
365 os::Printer::log("GLX window was not properly created.", ELL_WARNING);
\r
371 context = glXCreateContext((Display*)CurrentContext.OpenGLLinux.X11Display, VisualInfo, NULL, True);
\r
374 os::Printer::log("Could not create GLX rendering context.", ELL_WARNING);
\r
378 CurrentContext.OpenGLLinux.X11Context=context;
\r
382 const SExposedVideoData& CGLXManager::getContext() const
\r
384 return CurrentContext;
\r
387 bool CGLXManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero)
\r
389 //TODO: handle restorePrimaryOnZero
\r
391 if (videoData.OpenGLLinux.X11Window)
\r
393 if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context)
\r
395 if (!glXMakeCurrent((Display*)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.GLXWindow, (GLXContext)videoData.OpenGLLinux.X11Context))
\r
397 os::Printer::log("Context activation failed.");
\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
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
412 os::Printer::log("Context activation failed.");
\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
423 else if (!restorePrimaryOnZero && !videoData.OpenGLLinux.X11Window && !videoData.OpenGLLinux.X11Display)
\r
425 if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, None, NULL))
\r
427 os::Printer::log("Render Context reset failed.");
\r
430 CurrentContext.OpenGLLinux.X11Window = 0;
\r
431 CurrentContext.OpenGLLinux.X11Display = 0;
\r
433 // set back to main context
\r
434 else if (CurrentContext.OpenGLLinux.X11Display != PrimaryContext.OpenGLLinux.X11Display)
\r
436 if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, PrimaryContext.OpenGLLinux.X11Window, (GLXContext)PrimaryContext.OpenGLLinux.X11Context))
\r
438 os::Printer::log("Context activation failed.");
\r
443 CurrentContext = PrimaryContext;
\r
449 void CGLXManager::destroyContext()
\r
451 if (CurrentContext.OpenGLLinux.X11Context)
\r
455 if (!glXMakeContextCurrent((Display*)CurrentContext.OpenGLLinux.X11Display, None, None, NULL))
\r
456 os::Printer::log("Could not release glx context.", ELL_WARNING);
\r
460 if (!glXMakeCurrent((Display*)CurrentContext.OpenGLLinux.X11Display, None, NULL))
\r
461 os::Printer::log("Could not release glx context.", ELL_WARNING);
\r
463 glXDestroyContext((Display*)CurrentContext.OpenGLLinux.X11Display, (GLXContext)CurrentContext.OpenGLLinux.X11Context);
\r
467 void* CGLXManager::getProcAddress(const std::string &procName)
\r
469 return (void*)glXGetProcAddressARB(reinterpret_cast<const GLubyte*>(procName.c_str()));
\r
472 bool CGLXManager::swapBuffers()
\r
474 glXSwapBuffers((Display*)CurrentContext.OpenGLLinux.X11Display, CurrentContext.OpenGLLinux.GLXWindow);
\r