5 #include <msp/strings/utils.h>
7 #include "display_private.h"
8 #include "window_private.h"
15 typedef GLXContext ContextHandle;
17 struct GLContext::Private
19 ContextHandle context;
20 // We need to create a window with the chosen visual
26 void GLContext::platform_init(const GLOptions &opts)
28 DisplayHandle dpy = display.get_private().display;
31 if(!glXQueryExtension(dpy, &event_base, &error_base))
32 throw runtime_error("glX not found");
35 glXQueryVersion(dpy, &major, &minor);
37 set<string> extensions;
38 if(major>1 || (major==1 && minor>=1))
40 if(const char *ext_str = glXQueryExtensionsString(dpy, DefaultScreen(dpy)))
42 vector<string> exts = split(ext_str);
43 extensions.insert(exts.begin(), exts.end());
47 if(major>1 || (major==1 && minor>=3))
49 vector<int> fb_attribs;
51 fb_attribs.push_back(GLX_DRAWABLE_TYPE);
52 fb_attribs.push_back(GLX_WINDOW_BIT);
54 fb_attribs.push_back(GLX_RENDER_TYPE);
55 fb_attribs.push_back(GLX_RGBA_BIT);
57 fb_attribs.push_back(GLX_DEPTH_SIZE);
58 fb_attribs.push_back(1);
62 fb_attribs.push_back(GLX_ALPHA_SIZE);
63 fb_attribs.push_back(1);
68 fb_attribs.push_back(GLX_STENCIL_SIZE);
69 fb_attribs.push_back(1);
72 fb_attribs.push_back(GLX_DOUBLEBUFFER);
73 fb_attribs.push_back(opts.doublebuffer);
75 if(opts.multisample>0)
77 fb_attribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
78 fb_attribs.push_back(1);
79 fb_attribs.push_back(GLX_SAMPLES_ARB);
80 fb_attribs.push_back(opts.multisample);
83 fb_attribs.push_back(0);
86 GLXFBConfig *fb_configs = glXChooseFBConfig(dpy, DefaultScreen(dpy), &fb_attribs[0], &n_configs);
88 throw unsupported_gl_mode(opts);
90 XVisualInfo *vi = glXGetVisualFromFBConfig(dpy, fb_configs[0]);
92 XSetWindowAttributes attr;
93 attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
96 priv->subwnd = XCreateWindow(dpy, window.get_private().window, 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
97 XMapWindow(dpy, priv->subwnd);
99 priv->glxwnd = glXCreateWindow(dpy, fb_configs[0], priv->subwnd, 0);
101 if(opts.forward_compatible || opts.gl_version_major)
103 if(!extensions.count("GLX_ARB_create_context") || !extensions.count("GLX_ARB_get_proc_address"))
104 throw unsupported_gl_mode(opts);
106 vector<int> ctx_attribs;
108 ctx_attribs.push_back(GLX_RENDER_TYPE);
109 ctx_attribs.push_back(GLX_RGBA_TYPE);
111 if(opts.forward_compatible)
113 ctx_attribs.push_back(GLX_CONTEXT_FLAGS_ARB);
114 ctx_attribs.push_back(GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
117 if(opts.core_profile)
119 ctx_attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
120 ctx_attribs.push_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
123 if(opts.gl_version_major)
125 ctx_attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
126 ctx_attribs.push_back(opts.gl_version_major);
127 ctx_attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
128 ctx_attribs.push_back(opts.gl_version_minor);
131 ctx_attribs.push_back(0);
133 const GLubyte *name = reinterpret_cast<const GLubyte *>("glXCreateContextAttribsARB");
134 PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddressARB(name));
135 priv->context = glXCreateContextAttribs(dpy, fb_configs[0], 0, true, &ctx_attribs[0]);
138 priv->context = glXCreateNewContext(dpy, fb_configs[0], GLX_RGBA_TYPE, 0, true);
143 glXMakeContextCurrent(dpy, priv->glxwnd, priv->glxwnd, priv->context);
145 else if(opts.forward_compatible || opts.gl_version_major)
146 throw unsupported_gl_mode(opts);
151 attribs.push_back(GLX_RGBA);
152 attribs.push_back(GLX_DEPTH_SIZE);
153 attribs.push_back(1);
157 attribs.push_back(GLX_ALPHA_SIZE);
158 attribs.push_back(1);
163 attribs.push_back(GLX_STENCIL_SIZE);
164 attribs.push_back(1);
167 if(opts.doublebuffer)
168 attribs.push_back(GLX_DOUBLEBUFFER);
170 if(opts.multisample>0)
172 attribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
173 attribs.push_back(1);
174 attribs.push_back(GLX_SAMPLES_ARB);
175 attribs.push_back(opts.multisample);
178 attribs.push_back(0);
180 XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front());
182 throw unsupported_gl_mode(opts);
186 priv->context = glXCreateContext(dpy, vi, 0, true);
188 XSetWindowAttributes attr;
189 attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
191 priv->subwnd = XCreateWindow(dpy, window.get_private().window, 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
192 XMapWindow(dpy, priv->subwnd);
196 glXMakeCurrent(dpy, priv->subwnd, priv->context);
200 GLContext::~GLContext()
202 DisplayHandle dpy = display.get_private().display;
206 glXMakeContextCurrent(dpy, 0, 0, 0);
207 glXDestroyWindow(dpy, priv->glxwnd);
210 glXMakeCurrent(dpy, 0, 0);
211 glXDestroyContext(dpy, priv->context);
212 XDestroyWindow(dpy, priv->subwnd);
217 void GLContext::set_swap_interval(unsigned i)
219 const GLubyte *name = reinterpret_cast<const GLubyte *>("glXSwapIntervalEXT");
220 PFNGLXSWAPINTERVALEXTPROC glXSwapInterval = reinterpret_cast<PFNGLXSWAPINTERVALEXTPROC>(glXGetProcAddress(name));
222 throw runtime_error("glXSwapIntervalEXT not found");
223 glXSwapInterval(display.get_private().display, (priv->glxwnd ? priv->glxwnd : priv->subwnd), i);
226 void GLContext::swap_buffers()
228 glXSwapBuffers(display.get_private().display, (priv->glxwnd ? priv->glxwnd : priv->subwnd));
231 void GLContext::window_resized(unsigned w, unsigned h)
233 XMoveResizeWindow(display.get_private().display, priv->subwnd, 0, 0, w, h);
236 } // namespace Graphics