fix the confusion in boolean attributes handling in pre-1.3 and 1.3 versions of GLX...
[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 #include "wx/log.h"
26 #endif //WX_PRECOMP
27
28 #include "wx/glcanvas.h"
29
30 // ============================================================================
31 // wxGLContext implementation
32 // ============================================================================
33
34 IMPLEMENT_CLASS(wxGLContext, wxObject)
35
36 wxGLContext::wxGLContext(wxGLCanvas *gc, const wxGLContext *other)
37 {
38 if ( wxGLCanvas::GetGLXVersion() >= 13 )
39 {
40 GLXFBConfig *fbc = gc->GetGLXFBConfig();
41 wxCHECK_RET( fbc, _T("invalid GLXFBConfig for OpenGL") );
42
43 m_glContext = glXCreateNewContext( wxGetX11Display(), fbc[0], GLX_RGBA_TYPE,
44 other ? other->m_glContext : None,
45 GL_TRUE );
46 }
47 else // GLX <= 1.2
48 {
49 XVisualInfo *vi = gc->GetXVisualInfo();
50 wxCHECK_RET( vi, _T("invalid visual for OpenGL") );
51
52 m_glContext = glXCreateContext( wxGetX11Display(), vi,
53 other ? other->m_glContext : None,
54 GL_TRUE );
55 }
56
57 wxASSERT_MSG( m_glContext, _T("Couldn't create OpenGL context") );
58 }
59
60 wxGLContext::~wxGLContext()
61 {
62 if ( !m_glContext )
63 return;
64
65 if ( m_glContext == glXGetCurrentContext() )
66 MakeCurrent(None, NULL);
67
68 glXDestroyContext( wxGetX11Display(), m_glContext );
69 }
70
71 bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
72 {
73 if ( !m_glContext )
74 return false;
75
76 const Window xid = win.GetXWindow();
77 wxCHECK2_MSG( xid, return false, _T("window must be shown") );
78
79 return MakeCurrent(xid, m_glContext);
80 }
81
82 // wrapper around glXMakeContextCurrent/glXMakeCurrent depending on GLX
83 // version
84 /* static */
85 bool wxGLContext::MakeCurrent(GLXDrawable drawable, GLXContext context)
86 {
87 if (wxGLCanvas::GetGLXVersion() >= 13)
88 return glXMakeContextCurrent( wxGetX11Display(), drawable, drawable, context);
89 else // GLX <= 1.2 doesn't have glXMakeContextCurrent()
90 return glXMakeCurrent( wxGetX11Display(), drawable, context);
91 }
92
93 // ============================================================================
94 // wxGLCanvasX11 implementation
95 // ============================================================================
96
97 // ----------------------------------------------------------------------------
98 // initialization methods and dtor
99 // ----------------------------------------------------------------------------
100
101 wxGLCanvasX11::wxGLCanvasX11()
102 {
103 m_fbc = NULL;
104 m_vi = NULL;
105 }
106
107 bool wxGLCanvasX11::InitVisual(const int *attribList)
108 {
109 return InitXVisualInfo(attribList, &m_fbc, &m_vi);
110 }
111
112 wxGLCanvasX11::~wxGLCanvasX11()
113 {
114 if ( m_fbc && m_fbc != ms_glFBCInfo )
115 XFree(m_fbc);
116
117 if ( m_vi && m_vi != ms_glVisualInfo )
118 XFree(m_vi);
119 }
120
121 // ----------------------------------------------------------------------------
122 // working with GL attributes
123 // ----------------------------------------------------------------------------
124
125 bool
126 wxGLCanvasX11::ConvertWXAttrsToGL(const int *wxattrs, int *glattrs, size_t n)
127 {
128 wxCHECK_MSG( n >= 16, false, _T("GL attributes buffer too small") );
129
130 /*
131 Different versions of GLX API use rather different attributes lists, see
132 the following URLs:
133
134 - <= 1.2: http://www.opengl.org/sdk/docs/man/xhtml/glXChooseVisual.xml
135 - >= 1.3: http://www.opengl.org/sdk/docs/man/xhtml/glXChooseFBConfig.xml
136
137 Notice in particular that
138 - GLX_RGBA is boolean attribute in the old version of the API but a
139 value of GLX_RENDER_TYPE in the new one
140 - Boolean attributes such as GLX_DOUBLEBUFFER don't take values in the
141 old version but must be followed by True or False in the new one.
142 */
143
144 if ( !wxattrs )
145 {
146 size_t i = 0;
147
148 // use double-buffered true colour by default
149 glattrs[i++] = GLX_DOUBLEBUFFER;
150
151 if ( GetGLXVersion() < 13 )
152 {
153 // default settings if attriblist = 0
154 glattrs[i++] = GLX_RGBA;
155 glattrs[i++] = GLX_DEPTH_SIZE; glattrs[i++] = 1;
156 glattrs[i++] = GLX_RED_SIZE; glattrs[i++] = 1;
157 glattrs[i++] = GLX_GREEN_SIZE; glattrs[i++] = 1;
158 glattrs[i++] = GLX_BLUE_SIZE; glattrs[i++] = 1;
159 glattrs[i++] = GLX_ALPHA_SIZE; glattrs[i++] = 0;
160 }
161 else // recent GLX can choose the defaults on its own just fine
162 {
163 // we just need to have a value after GLX_DOUBLEBUFFER
164 glattrs[i++] = True;
165 }
166
167 glattrs[i] = None;
168
169 wxASSERT_MSG( i < n, _T("GL attributes buffer too small") );
170 }
171 else // have non-default attributes
172 {
173 size_t p = 0;
174 for ( int arg = 0; wxattrs[arg] != 0; )
175 {
176 // check if we have any space left, knowing that we may insert 2
177 // more elements during this loop iteration and we always need to
178 // terminate the list with None (hence -3)
179 if ( p > n - 3 )
180 return false;
181
182 // indicates whether we have a boolean attribute
183 bool isBoolAttr = false;
184
185 switch ( wxattrs[arg++] )
186 {
187 case WX_GL_BUFFER_SIZE:
188 glattrs[p++] = GLX_BUFFER_SIZE;
189 break;
190
191 case WX_GL_LEVEL:
192 glattrs[p++] = GLX_LEVEL;
193 break;
194
195 case WX_GL_RGBA:
196 if ( GetGLXVersion() >= 13 )
197 {
198 // this is the default GLX_RENDER_TYPE anyhow
199 continue;
200 }
201
202 glattrs[p++] = GLX_RGBA;
203 isBoolAttr = true;
204 break;
205
206 case WX_GL_DOUBLEBUFFER:
207 glattrs[p++] = GLX_DOUBLEBUFFER;
208 isBoolAttr = true;
209 break;
210
211 case WX_GL_STEREO:
212 glattrs[p++] = GLX_STEREO;
213 isBoolAttr = true;
214 break;
215
216 case WX_GL_AUX_BUFFERS:
217 glattrs[p++] = GLX_AUX_BUFFERS;
218 break;
219
220 case WX_GL_MIN_RED:
221 glattrs[p++] = GLX_RED_SIZE;
222 break;
223
224 case WX_GL_MIN_GREEN:
225 glattrs[p++] = GLX_GREEN_SIZE;
226 break;
227
228 case WX_GL_MIN_BLUE:
229 glattrs[p++] = GLX_BLUE_SIZE;
230 break;
231
232 case WX_GL_MIN_ALPHA:
233 glattrs[p++] = GLX_ALPHA_SIZE;
234 break;
235
236 case WX_GL_DEPTH_SIZE:
237 glattrs[p++] = GLX_DEPTH_SIZE;
238 break;
239
240 case WX_GL_STENCIL_SIZE:
241 glattrs[p++] = GLX_STENCIL_SIZE;
242 break;
243
244 case WX_GL_MIN_ACCUM_RED:
245 glattrs[p++] = GLX_ACCUM_RED_SIZE;
246 break;
247
248 case WX_GL_MIN_ACCUM_GREEN:
249 glattrs[p++] = GLX_ACCUM_GREEN_SIZE;
250 break;
251
252 case WX_GL_MIN_ACCUM_BLUE:
253 glattrs[p++] = GLX_ACCUM_BLUE_SIZE;
254 break;
255
256 case WX_GL_MIN_ACCUM_ALPHA:
257 glattrs[p++] = GLX_ACCUM_ALPHA_SIZE;
258 break;
259
260 default:
261 wxLogDebug(_T("Unsupported OpenGL attribute %d"),
262 wxattrs[arg - 1]);
263 continue;
264 }
265
266 if ( isBoolAttr )
267 {
268 // as explained above, for pre 1.3 API the attribute just needs
269 // to be present so we only add its value when using the new API
270 if ( GetGLXVersion() >= 13 )
271 glattrs[p++] = True;
272 }
273 else // attribute with real (non-boolean) value
274 {
275 // copy attribute value as is
276 glattrs[p++] = wxattrs[arg++];
277 }
278 }
279
280 glattrs[p] = None;
281 }
282
283 return true;
284 }
285
286 /* static */
287 bool
288 wxGLCanvasX11::InitXVisualInfo(const int *attribList,
289 GLXFBConfig **pFBC,
290 XVisualInfo **pXVisual)
291 {
292 int data[512];
293 if ( !ConvertWXAttrsToGL(attribList, data, WXSIZEOF(data)) )
294 return false;
295
296 Display * const dpy = wxGetX11Display();
297
298 if ( GetGLXVersion() >= 13 )
299 {
300 int returned;
301 *pFBC = glXChooseFBConfig(dpy, DefaultScreen(dpy), data, &returned);
302
303 if ( *pFBC )
304 {
305 *pXVisual = glXGetVisualFromFBConfig(wxGetX11Display(), **pFBC);
306 if ( !*pXVisual )
307 {
308 XFree(*pFBC);
309 *pFBC = NULL;
310 }
311 }
312 }
313 else // GLX <= 1.2
314 {
315 *pFBC = NULL;
316 *pXVisual = glXChooseVisual(dpy, DefaultScreen(dpy), data);
317 }
318
319 return *pXVisual != NULL;
320 }
321
322 /* static */
323 bool
324 wxGLCanvasBase::IsDisplaySupported(const int *attribList)
325 {
326 GLXFBConfig *fbc = NULL;
327 XVisualInfo *vi = NULL;
328
329 const bool
330 isSupported = wxGLCanvasX11::InitXVisualInfo(attribList, &fbc, &vi);
331
332 if ( fbc )
333 XFree(fbc);
334 if ( vi )
335 XFree(vi);
336
337 return isSupported;
338 }
339
340 // ----------------------------------------------------------------------------
341 // default visual management
342 // ----------------------------------------------------------------------------
343
344 XVisualInfo *wxGLCanvasX11::ms_glVisualInfo = NULL;
345 GLXFBConfig *wxGLCanvasX11::ms_glFBCInfo = NULL;
346
347 /* static */
348 bool wxGLCanvasX11::InitDefaultVisualInfo(const int *attribList)
349 {
350 FreeDefaultVisualInfo();
351
352 return InitXVisualInfo(attribList, &ms_glFBCInfo, &ms_glVisualInfo);
353 }
354
355 /* static */
356 void wxGLCanvasX11::FreeDefaultVisualInfo()
357 {
358 if ( ms_glFBCInfo )
359 {
360 XFree(ms_glFBCInfo);
361 ms_glFBCInfo = NULL;
362 }
363
364 if ( ms_glVisualInfo )
365 {
366 XFree(ms_glVisualInfo);
367 ms_glVisualInfo = NULL;
368 }
369 }
370
371 // ----------------------------------------------------------------------------
372 // other GL methods
373 // ----------------------------------------------------------------------------
374
375 /* static */
376 int wxGLCanvasX11::GetGLXVersion()
377 {
378 static int s_glxVersion = 0;
379 if ( s_glxVersion == 0 )
380 {
381 // check the GLX version
382 int glxMajorVer, glxMinorVer;
383 bool ok = glXQueryVersion(wxGetX11Display(), &glxMajorVer, &glxMinorVer);
384 wxASSERT_MSG( ok, _T("GLX version not found") );
385 if (!ok)
386 s_glxVersion = 10; // 1.0 by default
387 else
388 s_glxVersion = glxMajorVer*10 + glxMinorVer;
389 }
390
391 return s_glxVersion;
392 }
393
394 bool wxGLCanvasX11::SwapBuffers()
395 {
396 const Window xid = GetXWindow();
397 wxCHECK2_MSG( xid, return false, _T("window must be shown") );
398
399 glXSwapBuffers(wxGetX11Display(), xid);
400 return true;
401 }
402
403 bool wxGLCanvasX11::IsShownOnScreen() const
404 {
405 return GetXWindow() && wxGLCanvasBase::IsShownOnScreen();
406 }
407
408 #endif // wxUSE_GLCANVAS
409