]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/glx/glcontext.cpp
Add a core profile flag to OpenGL context options
[libs/gui.git] / source / graphics / glx / glcontext.cpp
1 #include <set>
2 #include <vector>
3 #include <GL/glx.h>
4 #include <GL/glxext.h>
5 #include <msp/strings/utils.h>
6 #include "glcontext.h"
7 #include "display_private.h"
8 #include "window_private.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace Graphics {
14
15 typedef GLXContext ContextHandle;
16
17 struct GLContext::Private
18 {
19         ContextHandle context;
20         // We need to create a window with the chosen visual
21         WindowHandle subwnd;
22         GLXWindow glxwnd;
23 };
24
25
26 void GLContext::platform_init(const GLOptions &opts)
27 {
28         DisplayHandle dpy = display.get_private().display;
29         int event_base;
30         int error_base;
31         if(!glXQueryExtension(dpy, &event_base, &error_base))
32                 throw runtime_error("glX not found");
33
34         int major, minor;
35         glXQueryVersion(dpy, &major, &minor);
36
37         set<string> extensions;
38         if(major>1 || (major==1 && minor>=1))
39         {
40                 if(const char *ext_str = glXQueryExtensionsString(dpy, DefaultScreen(dpy)))
41                 {
42                         vector<string> exts = split(ext_str);
43                         extensions.insert(exts.begin(), exts.end());
44                 }
45         }
46
47         if(major>1 || (major==1 && minor>=3))
48         {
49                 vector<int> fb_attribs;
50
51                 fb_attribs.push_back(GLX_DRAWABLE_TYPE);
52                 fb_attribs.push_back(GLX_WINDOW_BIT);
53
54                 fb_attribs.push_back(GLX_RENDER_TYPE);
55                 fb_attribs.push_back(GLX_RGBA_BIT);
56
57                 fb_attribs.push_back(GLX_DEPTH_SIZE);
58                 fb_attribs.push_back(1);
59
60                 if(opts.alpha)
61                 {
62                         fb_attribs.push_back(GLX_ALPHA_SIZE);
63                         fb_attribs.push_back(1);
64                 }
65
66                 if(opts.stencil)
67                 {
68                         fb_attribs.push_back(GLX_STENCIL_SIZE);
69                         fb_attribs.push_back(1);
70                 }
71
72                 fb_attribs.push_back(GLX_DOUBLEBUFFER);
73                 fb_attribs.push_back(opts.doublebuffer);
74
75                 if(opts.multisample>0)
76                 {
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);
81                 }
82
83                 fb_attribs.push_back(0);
84
85                 int n_configs = 0;
86                 GLXFBConfig *fb_configs = glXChooseFBConfig(dpy, DefaultScreen(dpy), &fb_attribs[0], &n_configs);
87                 if(!fb_configs)
88                         throw unsupported_gl_mode(opts);
89
90                 XVisualInfo *vi = glXGetVisualFromFBConfig(dpy, fb_configs[0]);
91
92                 XSetWindowAttributes attr;
93                 attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
94
95                 priv = new Private;
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);
98
99                 priv->glxwnd = glXCreateWindow(dpy, fb_configs[0], priv->subwnd, 0);
100
101                 if(opts.forward_compatible || opts.gl_version_major)
102                 {
103                         if(!extensions.count("GLX_ARB_create_context") || !extensions.count("GLX_ARB_get_proc_address"))
104                                 throw unsupported_gl_mode(opts);
105
106                         vector<int> ctx_attribs;
107
108                         ctx_attribs.push_back(GLX_RENDER_TYPE);
109                         ctx_attribs.push_back(GLX_RGBA_TYPE);
110
111                         if(opts.forward_compatible)
112                         {
113                                 ctx_attribs.push_back(GLX_CONTEXT_FLAGS_ARB);
114                                 ctx_attribs.push_back(GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
115                         }
116
117                         if(opts.core_profile)
118                         {
119                                 ctx_attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
120                                 ctx_attribs.push_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
121                         }
122
123                         if(opts.gl_version_major)
124                         {
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);
129                         }
130
131                         ctx_attribs.push_back(0);
132
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]);
136                 }
137                 else
138                         priv->context = glXCreateNewContext(dpy, fb_configs[0], GLX_RGBA_TYPE, 0, true);
139
140                 XFree(vi);
141                 XFree(fb_configs);
142
143                 glXMakeContextCurrent(dpy, priv->glxwnd, priv->glxwnd, priv->context);
144         }
145         else if(opts.forward_compatible || opts.gl_version_major)
146                 throw unsupported_gl_mode(opts);
147         else
148         {
149                 vector<int> attribs;
150
151                 attribs.push_back(GLX_RGBA);
152                 attribs.push_back(GLX_DEPTH_SIZE);
153                 attribs.push_back(1);
154
155                 if(opts.alpha)
156                 {
157                         attribs.push_back(GLX_ALPHA_SIZE);
158                         attribs.push_back(1);
159                 }
160
161                 if(opts.stencil)
162                 {
163                         attribs.push_back(GLX_STENCIL_SIZE);
164                         attribs.push_back(1);
165                 }
166
167                 if(opts.doublebuffer)
168                         attribs.push_back(GLX_DOUBLEBUFFER);
169
170                 if(opts.multisample>0)
171                 {
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);
176                 }
177
178                 attribs.push_back(0);
179
180                 XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front());
181                 if(!vi)
182                         throw unsupported_gl_mode(opts);
183
184                 priv = new Private;
185                 priv->glxwnd = 0;
186                 priv->context = glXCreateContext(dpy, vi, 0, true);
187
188                 XSetWindowAttributes attr;
189                 attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
190
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);
193
194                 XFree(vi);
195
196                 glXMakeCurrent(dpy, priv->subwnd, priv->context);
197         }
198 }
199
200 GLContext::~GLContext()
201 {
202         DisplayHandle dpy = display.get_private().display;
203
204         if(priv->glxwnd)
205         {
206                 glXMakeContextCurrent(dpy, 0, 0, 0);
207                 glXDestroyWindow(dpy, priv->glxwnd);
208         }
209         else
210                 glXMakeCurrent(dpy, 0, 0);
211         glXDestroyContext(dpy, priv->context);
212         XDestroyWindow(dpy, priv->subwnd);
213
214         delete priv;
215 }
216
217 void GLContext::set_swap_interval(unsigned i)
218 {
219         const GLubyte *name = reinterpret_cast<const GLubyte *>("glXSwapIntervalEXT");
220         PFNGLXSWAPINTERVALEXTPROC glXSwapInterval = reinterpret_cast<PFNGLXSWAPINTERVALEXTPROC>(glXGetProcAddress(name));
221         if(!glXSwapInterval)
222                 throw runtime_error("glXSwapIntervalEXT not found");
223         glXSwapInterval(display.get_private().display, (priv->glxwnd ? priv->glxwnd : priv->subwnd), i);
224 }
225
226 void GLContext::swap_buffers()
227 {
228         glXSwapBuffers(display.get_private().display, (priv->glxwnd ? priv->glxwnd : priv->subwnd));
229 }
230
231 void GLContext::window_resized(unsigned w, unsigned h)
232 {
233         XMoveResizeWindow(display.get_private().display, priv->subwnd, 0, 0, w, h);
234 }
235
236 } // namespace Graphics
237 } // namespace Msp