/* * CINELERRA * Copyright (C) 2008 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #define GL_GLEXT_PROTOTYPES #include "bcpixmap.h" #include "bcresources.h" #include "bcsignals.h" #include "bcsynchronous.h" #include "bcwindowbase.h" #include "language.h" // OpenGL functions in BC_WindowBase #ifdef HAVE_GL int BC_WindowBase::glx_fb_configs(int *attrs, GLXFBConfig *&cfgs) { int ncfgs = 0; cfgs = glXChooseFBConfig(get_display(), get_screen(), attrs, &ncfgs); if( !cfgs ) ncfgs = 0; else if( !ncfgs && cfgs ) { XFree(cfgs); cfgs = 0; } return ncfgs; } // expects prefix of attrs to be: // GLX_CONFIG_CAVEAT, , // GLX_DRAWABLE_TYPE, , // GLX_DOUBLEBUFFER, True, int BC_WindowBase::glx_test_fb_configs(int *attrs, GLXFBConfig *&cfgs, const char *msg, int &msgs) { int ncfgs = glx_fb_configs(attrs+2, cfgs); if( ncfgs ) return ncfgs; if( msgs < 1 ) { ++msgs; /* printf(_("%s: trying fallback 1\n"), msg); */ } ncfgs = glx_fb_configs(attrs+0, cfgs); if( ncfgs ) return ncfgs; if( msgs < 2 ) { ++msgs; /* printf(_("%s: trying single buffering\n"), msg); */ } attrs[5] = False; ncfgs = glx_fb_configs(attrs+0, cfgs); if( ncfgs ) return ncfgs; if( msgs < 3 ) { ++msgs; /* printf(_("%s: trying fallback 2\n"), msg); */ } ncfgs = glx_fb_configs(attrs+2, cfgs); if( ncfgs ) return ncfgs; if( msgs < 4 ) { ++msgs; /* printf(_("%s: trying attributes None\n"), msg); */ } ncfgs = glx_fb_configs(None, cfgs); if( ncfgs ) return ncfgs; disable_opengl(); printf(_("%s: opengl initialization failed failed\n"), msg); return 0; } GLXFBConfig *BC_WindowBase::glx_window_fb_configs() { static int msgs = 0; if( !glx_fbcfgs_window ) { int fb_attrs[] = { GLX_CONFIG_CAVEAT, GLX_SLOW_CONFIG, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT | GLX_PIXMAP_BIT, GLX_DOUBLEBUFFER, True, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_ACCUM_RED_SIZE, 1, GLX_ACCUM_GREEN_SIZE, 1, GLX_ACCUM_BLUE_SIZE, 1, GLX_ACCUM_ALPHA_SIZE, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, None }; n_fbcfgs_window = glx_test_fb_configs(fb_attrs, glx_fbcfgs_window, "BC_WindowBase::glx_window_fb_configs", msgs); } return glx_fbcfgs_window; } Visual *BC_WindowBase::get_glx_visual(Display *display) { Visual *visual = 0; XVisualInfo *vis_info = 0; GLXFBConfig *fb_cfgs = glx_window_fb_configs(); if( fb_cfgs ) { for( int i=0; !vis_info && ivisual; XFree(vis_info); } else glx_fb_config = 0; return visual; } GLXFBConfig *BC_WindowBase::glx_pbuffer_fb_configs() { static int msgs = 0; if( !glx_fbcfgs_pbuffer ) { int fb_attrs[] = { GLX_CONFIG_CAVEAT, GLX_SLOW_CONFIG, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PBUFFER_BIT | GLX_PIXMAP_BIT, GLX_DOUBLEBUFFER, True, //False, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_ACCUM_RED_SIZE, 1, GLX_ACCUM_GREEN_SIZE, 1, GLX_ACCUM_BLUE_SIZE, 1, GLX_ACCUM_ALPHA_SIZE, 1, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, None }; n_fbcfgs_pbuffer = glx_test_fb_configs(fb_attrs, glx_fbcfgs_pbuffer, "BC_WindowBase::glx_pbuffer_fb_configs", msgs); } return glx_fbcfgs_pbuffer; } GLXFBConfig *BC_WindowBase::glx_pixmap_fb_configs() { static int msgs = 0; if( !glx_fbcfgs_pixmap ) { static int fb_attrs[] = { GLX_CONFIG_CAVEAT, GLX_SLOW_CONFIG, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_PBUFFER_BIT, GLX_DOUBLEBUFFER, True, //False, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, None }; n_fbcfgs_pixmap = glx_test_fb_configs(fb_attrs, glx_fbcfgs_pixmap, "BC_WindowBase::glx_pixmap_fb_configs", msgs); } return glx_fbcfgs_pixmap; } GLXContext BC_WindowBase::glx_get_context() { if( !glx_win_context && top_level->glx_fb_config ) glx_win_context = glXCreateNewContext( top_level->get_display(), top_level->glx_fb_config, GLX_RGBA_TYPE, 0, True); if( !glx_win_context ) printf("BC_WindowBase::get_glx_context %d: failed\n", __LINE__); return glx_win_context; } void BC_WindowBase::sync_lock(const char *cp) { get_synchronous()->sync_lock(cp); } void BC_WindowBase::sync_unlock() { get_synchronous()->sync_unlock(); } GLXWindow BC_WindowBase::glx_window() { if( !glx_win ) { glx_win = glXCreateWindow(top_level->display, top_level->glx_fb_config, win, 0); } return glx_win; } bool BC_WindowBase::glx_make_current(GLXDrawable draw, GLXContext glx_ctxt) { return glXMakeContextCurrent(get_display(), draw, draw, glx_ctxt); } //#define GL_BUG #ifdef GL_BUG static void GLAPIENTRY glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ), type, severity, message ); } #endif bool BC_WindowBase::glx_make_current(GLXDrawable draw) { bool ret = glx_make_current(draw, glx_win_context); #ifdef GL_BUG //Enabling OpenGL debug output glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(glDebugCallback, 0); glEnable(GL_DEBUG_OUTPUT); #endif return ret; } #endif void BC_WindowBase::enable_opengl() { #ifdef HAVE_GL glx_win = glx_window(); if( !glx_win ) { printf("BC_WindowBase::enable_opengl %d: no glx window\n", __LINE__); exit(1); } GLXContext glx_context = glx_get_context(); if( !glx_context ) { printf("BC_WindowBase::enable_opengl %d: no glx context\n", __LINE__); exit(1); } top_level->sync_display(); get_synchronous()->is_pbuffer = 0; get_synchronous()->current_window = this; glx_make_current(glx_win, glx_context); #endif } void BC_WindowBase::disable_opengl() { #ifdef HAVE_GL // unsigned long valuemask = CWEventMask; // XSetWindowAttributes attributes; // attributes.event_mask = DEFAULT_EVENT_MASKS; // XChangeWindowAttributes(top_level->display, win, valuemask, &attributes); #endif } void BC_WindowBase::flip_opengl() { #ifdef HAVE_GL glXSwapBuffers(top_level->display, glx_win); glFlush(); #endif } int BC_WindowBase::get_shader(unsigned int *handle, const char *vert, const char *frag) { return get_resources()->get_synchronous()->get_shader(handle, vert, frag); } void BC_WindowBase::put_shader(unsigned int handle, const char *vert, const char *frag) { get_resources()->get_synchronous()->put_shader(handle, vert, frag); } int BC_WindowBase::get_opengl_server_version() { #ifdef HAVE_GL int maj, min; if(glXQueryVersion(get_display(), &maj, &min)) return 100 * maj + min; #endif return 0; }