Refactor all code common to X11 OpenGL implementations into glx11.h/.cpp
[wxWidgets.git] / src / unix / glx11.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/glx11.cpp
3 // Purpose: code common to all X11-based wxGLCanvas implementations
4 // Author: Vadim Zeitlin
5 // Created: 2007-04-15
6 // RCS-ID: $Id$
7 // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #if wxUSE_GLCANVAS
23
24 #ifndef WX_PRECOMP
25 #endif //WX_PRECOMP
26
27 #include "wx/glcanvas.h"
28
29 // ============================================================================
30 // wxGLContext implementation
31 // ============================================================================
32
33 IMPLEMENT_CLASS(wxGLContext, wxObject)
34
35 wxGLContext::wxGLContext(wxGLCanvas *gc, const wxGLContext *other)
36 {
37 if ( wxGLCanvas::GetGLXVersion() >= 13 )
38 {
39 GLXFBConfig *fbc = gc->GetGLXFBConfig();
40 wxCHECK_RET( fbc, _T("invalid GLXFBConfig for OpenGL") );
41
42 m_glContext = glXCreateNewContext( wxGetX11Display(), fbc[0], GLX_RGBA_TYPE,
43 other ? other->m_glContext : None,
44 GL_TRUE );
45 }
46 else // GLX <= 1.2
47 {
48 XVisualInfo *vi = gc->GetXVisualInfo();
49 wxCHECK_RET( vi, _T("invalid visual for OpenGL") );
50
51 m_glContext = glXCreateContext( wxGetX11Display(), vi,
52 other ? other->m_glContext : None,
53 GL_TRUE );
54 }
55
56 wxASSERT_MSG( m_glContext, _T("Couldn't create OpenGL context") );
57 }
58
59 wxGLContext::~wxGLContext()
60 {
61 if ( !m_glContext )
62 return;
63
64 if ( m_glContext == glXGetCurrentContext() )
65 MakeCurrent(None, NULL);
66
67 glXDestroyContext( wxGetX11Display(), m_glContext );
68 }
69
70 void wxGLContext::SetCurrent(const wxGLCanvas& win) const
71 {
72 if ( !m_glContext )
73 return;
74
75 const Window xid = win.GetXWindow();
76 wxCHECK_RET( xid, _T("window must be shown") );
77
78 MakeCurrent(xid, m_glContext);
79 }
80
81 // wrapper around glXMakeContextCurrent/glXMakeCurrent depending on GLX
82 // version
83 /* static */
84 void wxGLContext::MakeCurrent(GLXDrawable drawable, GLXContext context)
85 {
86 if (wxGLCanvas::GetGLXVersion() >= 13)
87 glXMakeContextCurrent( wxGetX11Display(), drawable, drawable, context);
88 else // GLX <= 1.2 doesn't have glXMakeContextCurrent()
89 glXMakeCurrent( wxGetX11Display(), drawable, context);
90 }
91
92 // ============================================================================
93 // wxGLCanvasX11 implementation
94 // ============================================================================
95
96 // ----------------------------------------------------------------------------
97 // initialization methods and dtor
98 // ----------------------------------------------------------------------------
99
100 wxGLCanvasX11::wxGLCanvasX11()
101 {
102 m_fbc = NULL;
103 m_vi = NULL;
104 }
105
106 bool wxGLCanvasX11::InitVisual(const int *attribList)
107 {
108 return InitXVisualInfo(attribList, &m_fbc, &m_vi);
109 }
110
111 wxGLCanvasX11::~wxGLCanvasX11()
112 {
113 if ( m_fbc && m_fbc != ms_glFBCInfo )
114 XFree(m_fbc);
115
116 if ( m_vi && m_vi != ms_glVisualInfo )
117 XFree(m_vi);
118 }
119
120 // ----------------------------------------------------------------------------
121 // working with GL attributes
122 // ----------------------------------------------------------------------------
123
124 bool
125 wxGLCanvasX11::ConvertWXAttrsToGL(const int *wxattrs, int *glattrs, size_t n)
126 {
127 wxCHECK_MSG( n >= 16, false, _T("GL attributes buffer too small") );
128
129 if ( !wxattrs )
130 {
131 if ( GetGLXVersion() >= 13 )
132 {
133 // leave GLX >= 1.3 choose the default attributes
134 glattrs[0] = None;
135 }
136 else // GLX < 1.3
137 {
138 // default settings if attriblist = 0
139 size_t i = 0;
140 glattrs[i++] = GLX_RGBA;
141 glattrs[i++] = GLX_DOUBLEBUFFER;
142 glattrs[i++] = GLX_DEPTH_SIZE; glattrs[i++] = 1;
143 glattrs[i++] = GLX_RED_SIZE; glattrs[i++] = 1;
144 glattrs[i++] = GLX_GREEN_SIZE; glattrs[i++] = 1;
145 glattrs[i++] = GLX_BLUE_SIZE; glattrs[i++] = 1;
146 glattrs[i++] = GLX_ALPHA_SIZE; glattrs[i++] = 0;
147 glattrs[i++] = None;
148
149 wxASSERT_MSG( i < n, _T("GL attributes buffer too small") );
150 }
151 }
152 else // have non-default attributes
153 {
154 size_t p = 0;
155 for ( int arg = 0; wxattrs[arg] != 0; )
156 {
157 // check if we have any space left, knowing that we may insert 2
158 // more elements during this loop iteration and we always need to
159 // terminate the list with None (hence -3)
160 if ( p >= n - 2 )
161 return false;
162
163 // notice that for boolean attributes we use "continue" in the
164 // switch to skip the assignment of the attribute value at the end
165 // of the loop which is done for integer attributes
166 switch ( wxattrs[arg++] )
167 {
168 case WX_GL_RGBA:
169 // for GLX >= 1.3, GLX_RGBA is useless and apparently
170 // harmful for some implementations
171 //
172 // FIXME: is this true?
173 if ( GetGLXVersion() <= 12 )
174 {
175 glattrs[p++] = GLX_RGBA;
176 }
177 continue;
178
179 case WX_GL_BUFFER_SIZE:
180 glattrs[p++] = GLX_BUFFER_SIZE;
181 break;
182
183 case WX_GL_LEVEL:
184 glattrs[p++] = GLX_LEVEL;
185 break;
186
187 case WX_GL_DOUBLEBUFFER:
188 glattrs[p++] = GLX_DOUBLEBUFFER;
189 continue;
190
191 case WX_GL_STEREO:
192 glattrs[p++] = GLX_STEREO;
193 break;
194
195 case WX_GL_AUX_BUFFERS:
196 glattrs[p++] = GLX_AUX_BUFFERS;
197 break;
198
199 case WX_GL_MIN_RED:
200 glattrs[p++] = GLX_RED_SIZE;
201 break;
202
203 case WX_GL_MIN_GREEN:
204 glattrs[p++] = GLX_GREEN_SIZE;
205 break;
206
207 case WX_GL_MIN_BLUE:
208 glattrs[p++] = GLX_BLUE_SIZE;
209 break;
210
211 case WX_GL_MIN_ALPHA:
212 glattrs[p++] = GLX_ALPHA_SIZE;
213 break;
214
215 case WX_GL_DEPTH_SIZE:
216 glattrs[p++] = GLX_DEPTH_SIZE;
217 break;
218
219 case WX_GL_STENCIL_SIZE:
220 glattrs[p++] = GLX_STENCIL_SIZE;
221 break;
222
223 case WX_GL_MIN_ACCUM_RED:
224 glattrs[p++] = GLX_ACCUM_RED_SIZE;
225 break;
226
227 case WX_GL_MIN_ACCUM_GREEN:
228 glattrs[p++] = GLX_ACCUM_GREEN_SIZE;
229 break;
230
231 case WX_GL_MIN_ACCUM_BLUE:
232 glattrs[p++] = GLX_ACCUM_BLUE_SIZE;
233 break;
234
235 case WX_GL_MIN_ACCUM_ALPHA:
236 glattrs[p++] = GLX_ACCUM_ALPHA_SIZE;
237 break;
238
239 default:
240 wxLogDebug(_T("Unsupported OpenGL attribute %d"),
241 wxattrs[arg - 1]);
242 continue;
243 }
244
245 // copy attribute value as is
246 glattrs[p++] = wxattrs[arg++];
247 }
248
249 glattrs[p] = None;
250 }
251
252 return true;
253 }
254
255 /* static */
256 bool
257 wxGLCanvasX11::InitXVisualInfo(const int *attribList,
258 GLXFBConfig **pFBC,
259 XVisualInfo **pXVisual)
260 {
261 int data[512];
262 if ( !ConvertWXAttrsToGL(attribList, data, WXSIZEOF(data)) )
263 return false;
264
265 Display * const dpy = wxGetX11Display();
266
267 if ( GetGLXVersion() >= 13 )
268 {
269 int returned;
270 *pFBC = glXChooseFBConfig(dpy, DefaultScreen(dpy), data, &returned);
271
272 if ( *pFBC )
273 {
274 *pXVisual = glXGetVisualFromFBConfig(wxGetX11Display(), **pFBC);
275 if ( !*pXVisual )
276 {
277 XFree(*pFBC);
278 *pFBC = NULL;
279 }
280 }
281 }
282 else // GLX <= 1.2
283 {
284 *pFBC = NULL;
285 *pXVisual = glXChooseVisual(dpy, DefaultScreen(dpy), data);
286 }
287
288 return *pXVisual != NULL;
289 }
290
291 // ----------------------------------------------------------------------------
292 // default visual management
293 // ----------------------------------------------------------------------------
294
295 XVisualInfo *wxGLCanvasX11::ms_glVisualInfo = NULL;
296 GLXFBConfig *wxGLCanvasX11::ms_glFBCInfo = NULL;
297
298 /* static */
299 bool wxGLCanvasX11::InitDefaultVisualInfo(const int *attribList)
300 {
301 FreeDefaultVisualInfo();
302
303 return InitXVisualInfo(attribList, &ms_glFBCInfo, &ms_glVisualInfo);
304 }
305
306 /* static */
307 void wxGLCanvasX11::FreeDefaultVisualInfo()
308 {
309 if ( ms_glFBCInfo )
310 {
311 XFree(ms_glFBCInfo);
312 ms_glFBCInfo = NULL;
313 }
314
315 if ( ms_glVisualInfo )
316 {
317 XFree(ms_glVisualInfo);
318 ms_glVisualInfo = NULL;
319 }
320 }
321
322 // ----------------------------------------------------------------------------
323 // other GL methods
324 // ----------------------------------------------------------------------------
325
326 /* static */
327 int wxGLCanvasX11::GetGLXVersion()
328 {
329 static int s_glxVersion = 0;
330 if ( s_glxVersion == 0 )
331 {
332 // check the GLX version
333 int glxMajorVer, glxMinorVer;
334 bool ok = glXQueryVersion(wxGetX11Display(), &glxMajorVer, &glxMinorVer);
335 wxASSERT_MSG( ok, _T("GLX version not found") );
336 if (!ok)
337 s_glxVersion = 10; // 1.0 by default
338 else
339 s_glxVersion = glxMajorVer*10 + glxMinorVer;
340 }
341
342 return s_glxVersion;
343 }
344
345 void wxGLCanvasX11::SwapBuffers()
346 {
347 const Window xid = GetXWindow();
348 wxCHECK_RET( xid, _T("window must be shown") );
349
350 glXSwapBuffers(wxGetX11Display(), xid);
351 }
352
353 bool wxGLCanvasX11::IsShownOnScreen() const
354 {
355 return GetXWindow() && wxGLCanvasBase::IsShownOnScreen();
356 }
357
358 #endif // wxUSE_GLCANVAS
359