4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define GL_GLEXT_PROTOTYPES
24 #include "bcresources.h"
25 #include "bcsignals.h"
26 #include "bcsynchronous.h"
27 #include "bcwindowbase.h"
30 // OpenGL functions in BC_WindowBase
33 int BC_WindowBase::glx_fb_configs(int *attrs, GLXFBConfig *&cfgs)
36 cfgs = glXChooseFBConfig(get_display(), get_screen(), attrs, &ncfgs);
37 if( !cfgs ) ncfgs = 0;
38 else if( !ncfgs && cfgs ) { XFree(cfgs); cfgs = 0; }
42 // expects prefix of attrs to be:
43 // GLX_CONFIG_CAVEAT, <opt>,
44 // GLX_DRAWABLE_TYPE, <opt>,
45 // GLX_DOUBLEBUFFER, True,
46 int BC_WindowBase::glx_test_fb_configs(int *attrs, GLXFBConfig *&cfgs,
47 const char *msg, int &msgs)
49 int ncfgs = glx_fb_configs(attrs+2, cfgs);
50 if( ncfgs ) return ncfgs;
51 if( msgs < 1 ) { ++msgs; /* printf(_("%s: trying fallback 1\n"), msg); */ }
52 ncfgs = glx_fb_configs(attrs+0, cfgs);
53 if( ncfgs ) return ncfgs;
54 if( msgs < 2 ) { ++msgs; /* printf(_("%s: trying single buffering\n"), msg); */ }
56 ncfgs = glx_fb_configs(attrs+0, cfgs);
57 if( ncfgs ) return ncfgs;
58 if( msgs < 3 ) { ++msgs; /* printf(_("%s: trying fallback 2\n"), msg); */ }
59 ncfgs = glx_fb_configs(attrs+2, cfgs);
60 if( ncfgs ) return ncfgs;
61 if( msgs < 4 ) { ++msgs; /* printf(_("%s: trying attributes None\n"), msg); */ }
62 ncfgs = glx_fb_configs(None, cfgs);
63 if( ncfgs ) return ncfgs;
65 printf(_("%s: opengl initialization failed failed\n"), msg);
69 GLXFBConfig *BC_WindowBase::glx_window_fb_configs()
72 if( !glx_fbcfgs_window ) {
74 GLX_CONFIG_CAVEAT, GLX_SLOW_CONFIG,
75 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT | GLX_PIXMAP_BIT,
76 GLX_DOUBLEBUFFER, True,
77 GLX_RENDER_TYPE, GLX_RGBA_BIT,
78 GLX_ACCUM_RED_SIZE, 1,
79 GLX_ACCUM_GREEN_SIZE, 1,
80 GLX_ACCUM_BLUE_SIZE, 1,
81 GLX_ACCUM_ALPHA_SIZE, 1,
88 n_fbcfgs_window = glx_test_fb_configs(fb_attrs, glx_fbcfgs_window,
89 "BC_WindowBase::glx_window_fb_configs", msgs);
91 return glx_fbcfgs_window;
94 Visual *BC_WindowBase::get_glx_visual(Display *display)
97 XVisualInfo *vis_info = 0;
98 GLXFBConfig *fb_cfgs = glx_window_fb_configs();
100 for( int i=0; !vis_info && i<n_fbcfgs_window; ++i ) {
101 if( vis_info ) { XFree(vis_info); vis_info = 0; }
102 glx_fb_config = fb_cfgs[i];
103 vis_info = glXGetVisualFromFBConfig(display, glx_fb_config);
107 visual = vis_info->visual;
115 GLXFBConfig *BC_WindowBase::glx_pbuffer_fb_configs()
118 if( !glx_fbcfgs_pbuffer ) {
120 GLX_CONFIG_CAVEAT, GLX_SLOW_CONFIG,
121 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT | GLX_PIXMAP_BIT,
122 GLX_DOUBLEBUFFER, True, //False,
123 GLX_RENDER_TYPE, GLX_RGBA_BIT,
124 GLX_ACCUM_RED_SIZE, 1,
125 GLX_ACCUM_GREEN_SIZE, 1,
126 GLX_ACCUM_BLUE_SIZE, 1,
127 GLX_ACCUM_ALPHA_SIZE, 1,
134 n_fbcfgs_pbuffer = glx_test_fb_configs(fb_attrs, glx_fbcfgs_pbuffer,
135 "BC_WindowBase::glx_pbuffer_fb_configs", msgs);
137 return glx_fbcfgs_pbuffer;
140 GLXFBConfig *BC_WindowBase::glx_pixmap_fb_configs()
143 if( !glx_fbcfgs_pixmap ) {
144 static int fb_attrs[] = {
145 GLX_CONFIG_CAVEAT, GLX_SLOW_CONFIG,
146 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_PBUFFER_BIT,
147 GLX_DOUBLEBUFFER, True, //False,
148 GLX_RENDER_TYPE, GLX_RGBA_BIT,
155 n_fbcfgs_pixmap = glx_test_fb_configs(fb_attrs, glx_fbcfgs_pixmap,
156 "BC_WindowBase::glx_pixmap_fb_configs", msgs);
158 return glx_fbcfgs_pixmap;
161 GLXContext BC_WindowBase::glx_get_context()
163 if( !glx_win_context && top_level->glx_fb_config )
164 glx_win_context = glXCreateNewContext(
165 top_level->get_display(), top_level->glx_fb_config,
166 GLX_RGBA_TYPE, 0, True);
167 if( !glx_win_context )
168 printf("BC_WindowBase::get_glx_context %d: failed\n", __LINE__);
169 return glx_win_context;
172 void BC_WindowBase::sync_lock(const char *cp)
174 get_synchronous()->sync_lock(cp);
177 void BC_WindowBase::sync_unlock()
179 get_synchronous()->sync_unlock();
182 GLXWindow BC_WindowBase::glx_window()
185 glx_win = glXCreateWindow(top_level->display, top_level->glx_fb_config, win, 0);
190 bool BC_WindowBase::glx_make_current(GLXDrawable draw, GLXContext glx_ctxt)
192 return glXMakeContextCurrent(get_display(), draw, draw, glx_ctxt);
197 static void GLAPIENTRY glDebugCallback(GLenum source, GLenum type,
198 GLuint id, GLenum severity, GLsizei length, const GLchar* message,
199 const void* userParam)
201 fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
202 ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ),
203 type, severity, message );
207 bool BC_WindowBase::glx_make_current(GLXDrawable draw)
209 bool ret = glx_make_current(draw, glx_win_context);
211 //Enabling OpenGL debug output
212 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
213 glEnable(GL_DEBUG_OUTPUT);
214 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
215 glDebugMessageCallback(glDebugCallback, 0);
216 glEnable(GL_DEBUG_OUTPUT);
223 void BC_WindowBase::enable_opengl()
226 glx_win = glx_window();
228 printf("BC_WindowBase::enable_opengl %d: no glx window\n", __LINE__);
231 GLXContext glx_context = glx_get_context();
233 printf("BC_WindowBase::enable_opengl %d: no glx context\n", __LINE__);
236 top_level->sync_display();
237 get_synchronous()->is_pbuffer = 0;
238 get_synchronous()->current_window = this;
239 glx_make_current(glx_win, glx_context);
243 void BC_WindowBase::disable_opengl()
246 // unsigned long valuemask = CWEventMask;
247 // XSetWindowAttributes attributes;
248 // attributes.event_mask = DEFAULT_EVENT_MASKS;
249 // XChangeWindowAttributes(top_level->display, win, valuemask, &attributes);
253 void BC_WindowBase::flip_opengl()
256 glXSwapBuffers(top_level->display, glx_win);
261 int BC_WindowBase::get_shader(unsigned int *handle, const char *vert, const char *frag)
263 return get_resources()->get_synchronous()->get_shader(handle, vert, frag);
266 void BC_WindowBase::put_shader(unsigned int handle, const char *vert, const char *frag)
268 get_resources()->get_synchronous()->put_shader(handle, vert, frag);
271 int BC_WindowBase::get_opengl_server_version()
275 if(glXQueryVersion(get_display(), &maj, &min))
276 return 100 * maj + min;