5 #include <msp/strings/lexicalcast.h>
6 #include <msp/strings/utils.h>
8 #include "display_private.h"
9 #include "window_private.h"
16 typedef GLXContext ContextHandle;
18 struct GLContext::Private
20 ContextHandle context;
21 // We need to create a window with the chosen visual
27 void GLContext::platform_init(const GLOptions &opts)
29 DisplayHandle dpy = display.get_private().display;
32 if(!glXQueryExtension(dpy, &event_base, &error_base))
33 throw runtime_error("glX not found");
36 glXQueryVersion(dpy, &major, &minor);
38 set<string> extensions;
39 if(major>1 || (major==1 && minor>=1))
41 if(const char *ext_str = glXQueryExtensionsString(dpy, DefaultScreen(dpy)))
43 vector<string> exts = split(ext_str);
44 extensions.insert(exts.begin(), exts.end());
48 if(major>1 || (major==1 && minor>=3))
50 vector<int> fb_attribs;
52 fb_attribs.push_back(GLX_DRAWABLE_TYPE);
53 fb_attribs.push_back(GLX_WINDOW_BIT);
55 fb_attribs.push_back(GLX_RENDER_TYPE);
56 fb_attribs.push_back(GLX_RGBA_BIT);
58 fb_attribs.push_back(GLX_DEPTH_SIZE);
59 fb_attribs.push_back(1);
63 fb_attribs.push_back(GLX_ALPHA_SIZE);
64 fb_attribs.push_back(1);
69 fb_attribs.push_back(GLX_STENCIL_SIZE);
70 fb_attribs.push_back(1);
73 fb_attribs.push_back(GLX_DOUBLEBUFFER);
74 fb_attribs.push_back(opts.doublebuffer);
76 if(opts.multisample>0)
78 fb_attribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
79 fb_attribs.push_back(1);
80 fb_attribs.push_back(GLX_SAMPLES_ARB);
81 fb_attribs.push_back(opts.multisample);
84 fb_attribs.push_back(0);
87 GLXFBConfig *fb_configs = glXChooseFBConfig(dpy, DefaultScreen(dpy), &fb_attribs[0], &n_configs);
89 throw unsupported_gl_mode(opts);
91 XVisualInfo *vi = glXGetVisualFromFBConfig(dpy, fb_configs[0]);
93 XSetWindowAttributes attr;
94 attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
97 priv->subwnd = XCreateWindow(dpy, window.get_private().window, 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
98 XMapWindow(dpy, priv->subwnd);
100 priv->glxwnd = glXCreateWindow(dpy, fb_configs[0], priv->subwnd, 0);
102 if(opts.forward_compatible || opts.gl_version_major!=GLOptions::DEFAULT_VERSION)
104 if(!extensions.count("GLX_ARB_create_context") || !extensions.count("GLX_ARB_get_proc_address"))
105 throw unsupported_gl_mode(opts);
107 unsigned gl_version_major = opts.gl_version_major;
108 unsigned gl_version_minor = opts.gl_version_minor;
109 if(opts.gl_version_major==GLOptions::LATEST_VERSION)
111 ContextHandle probe_context = glXCreateNewContext(dpy, fb_configs[0], GLX_RGBA_TYPE, 0, true);
112 glXMakeContextCurrent(dpy, priv->glxwnd, priv->glxwnd, probe_context);
114 const char *gl_ver_ptr = reinterpret_cast<const char *>(glGetString(GL_VERSION));
116 throw unsupported_gl_mode(opts);
118 string gl_ver = gl_ver_ptr;
119 vector<string> parts = split(gl_ver.substr(0, gl_ver.find(' ')), '.');
121 gl_version_major = lexical_cast<unsigned>(parts[0]);
122 gl_version_minor = lexical_cast<unsigned>(parts[1]);
124 glXMakeContextCurrent(dpy, 0, 0, 0);
125 glXDestroyContext(dpy, probe_context);
128 vector<int> ctx_attribs;
130 ctx_attribs.push_back(GLX_RENDER_TYPE);
131 ctx_attribs.push_back(GLX_RGBA_TYPE);
133 if(opts.forward_compatible)
135 ctx_attribs.push_back(GLX_CONTEXT_FLAGS_ARB);
136 ctx_attribs.push_back(GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
139 if(opts.core_profile)
141 ctx_attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
142 ctx_attribs.push_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
145 if(opts.gl_version_major)
147 ctx_attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
148 ctx_attribs.push_back(gl_version_major);
149 ctx_attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
150 ctx_attribs.push_back(gl_version_minor);
153 ctx_attribs.push_back(0);
155 const GLubyte *name = reinterpret_cast<const GLubyte *>("glXCreateContextAttribsARB");
156 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddressARB(name));
157 priv->context = glXCreateContextAttribs(dpy, fb_configs[0], 0, true, &ctx_attribs[0]);
160 priv->context = glXCreateNewContext(dpy, fb_configs[0], GLX_RGBA_TYPE, 0, true);
165 glXMakeContextCurrent(dpy, priv->glxwnd, priv->glxwnd, priv->context);
167 else if(opts.forward_compatible || opts.gl_version_major)
168 throw unsupported_gl_mode(opts);
173 attribs.push_back(GLX_RGBA);
174 attribs.push_back(GLX_DEPTH_SIZE);
175 attribs.push_back(1);
179 attribs.push_back(GLX_ALPHA_SIZE);
180 attribs.push_back(1);
185 attribs.push_back(GLX_STENCIL_SIZE);
186 attribs.push_back(1);
189 if(opts.doublebuffer)
190 attribs.push_back(GLX_DOUBLEBUFFER);
192 if(opts.multisample>0)
194 attribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
195 attribs.push_back(1);
196 attribs.push_back(GLX_SAMPLES_ARB);
197 attribs.push_back(opts.multisample);
200 attribs.push_back(0);
202 XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front());
204 throw unsupported_gl_mode(opts);
208 priv->context = glXCreateContext(dpy, vi, 0, true);
210 XSetWindowAttributes attr;
211 attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
213 priv->subwnd = XCreateWindow(dpy, window.get_private().window, 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
214 XMapWindow(dpy, priv->subwnd);
218 glXMakeCurrent(dpy, priv->subwnd, priv->context);
222 GLContext::~GLContext()
224 DisplayHandle dpy = display.get_private().display;
228 glXMakeContextCurrent(dpy, 0, 0, 0);
229 glXDestroyWindow(dpy, priv->glxwnd);
232 glXMakeCurrent(dpy, 0, 0);
233 glXDestroyContext(dpy, priv->context);
234 XDestroyWindow(dpy, priv->subwnd);
239 void GLContext::set_swap_interval(unsigned i)
241 const GLubyte *name = reinterpret_cast<const GLubyte *>("glXSwapIntervalEXT");
242 PFNGLXSWAPINTERVALEXTPROC glXSwapInterval = reinterpret_cast<PFNGLXSWAPINTERVALEXTPROC>(glXGetProcAddress(name));
244 throw runtime_error("glXSwapIntervalEXT not found");
245 glXSwapInterval(display.get_private().display, (priv->glxwnd ? priv->glxwnd : priv->subwnd), i);
248 void GLContext::swap_buffers()
250 glXSwapBuffers(display.get_private().display, (priv->glxwnd ? priv->glxwnd : priv->subwnd));
253 void GLContext::window_resized(unsigned w, unsigned h)
255 XMoveResizeWindow(display.get_private().display, priv->subwnd, 0, 0, w, h);
258 } // namespace Graphics