nkeynes@94: /** nkeynes@405: * $Id: video_x11.c,v 1.14 2007-09-28 07:24:14 nkeynes Exp $ nkeynes@94: * nkeynes@103: * Shared functions for all X11-based display drivers. nkeynes@94: * nkeynes@94: * Copyright (c) 2005 Nathan Keynes. nkeynes@94: * nkeynes@94: * This program is free software; you can redistribute it and/or modify nkeynes@94: * it under the terms of the GNU General Public License as published by nkeynes@94: * the Free Software Foundation; either version 2 of the License, or nkeynes@94: * (at your option) any later version. nkeynes@94: * nkeynes@94: * This program is distributed in the hope that it will be useful, nkeynes@94: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@94: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@94: * GNU General Public License for more details. nkeynes@94: */ nkeynes@94: nkeynes@103: #include nkeynes@103: #include nkeynes@103: #include "dream.h" nkeynes@94: #include "drivers/video_x11.h" nkeynes@405: #include "drivers/gl_common.h" nkeynes@94: nkeynes@352: extern uint32_t video_width, video_height; nkeynes@352: nkeynes@103: /** nkeynes@103: * General X11 parameters. The front-end driver is expected to set this up nkeynes@352: * by calling video_glx_init after initializing itself. nkeynes@103: */ nkeynes@352: static Display *video_x11_display = NULL; nkeynes@352: static Screen *video_x11_screen = NULL; nkeynes@352: static Window video_x11_window = 0; nkeynes@405: static gboolean glsl_loaded = FALSE; nkeynes@352: nkeynes@103: /** nkeynes@103: * GLX parameters. nkeynes@103: */ nkeynes@352: static GLXContext glx_context; nkeynes@352: static Window glx_window; nkeynes@352: static XSetWindowAttributes win_attrs; nkeynes@103: nkeynes@352: gboolean video_glx_init( Display *display, Screen *screen, Window window, nkeynes@352: int width, int height, display_driver_t driver ) nkeynes@94: { nkeynes@94: video_x11_display = display; nkeynes@94: video_x11_screen = screen; nkeynes@94: video_x11_window = window; nkeynes@352: nkeynes@352: if( !video_glx_create_window(width,height) ) { nkeynes@352: return FALSE; nkeynes@352: } nkeynes@352: nkeynes@352: if( gl_fbo_is_supported() ) { nkeynes@352: gl_fbo_init(driver); nkeynes@405: nkeynes@405: #ifdef USE_GLSL nkeynes@405: if( glsl_is_supported() ) { nkeynes@405: glsl_loaded = glsl_load_shaders( glsl_vertex_shader_src, glsl_fragment_shader_src ); nkeynes@405: if( !glsl_loaded ) { nkeynes@405: WARN( "Shaders failed to load" ); nkeynes@405: } nkeynes@405: } else { nkeynes@405: WARN( "Shaders not supported" ); nkeynes@405: } nkeynes@405: #endif nkeynes@352: return TRUE; nkeynes@352: } else { nkeynes@352: /* Pbuffers? */ nkeynes@352: ERROR( "Framebuffer objects not supported (required in this version)" ); nkeynes@352: video_glx_shutdown(); nkeynes@352: return FALSE; nkeynes@352: } nkeynes@94: } nkeynes@94: nkeynes@352: gboolean video_glx_create_window( int width, int height ) nkeynes@103: { nkeynes@103: int major, minor; nkeynes@103: const char *glxExts, *glxServer; nkeynes@103: int visual_attrs[] = { GLX_RGBA, GLX_RED_SIZE, 4, nkeynes@103: GLX_GREEN_SIZE, 4, nkeynes@103: GLX_BLUE_SIZE, 4, nkeynes@103: GLX_ALPHA_SIZE, 4, nkeynes@335: GLX_DEPTH_SIZE, 24, nkeynes@103: GLX_DOUBLEBUFFER, nkeynes@103: None }; nkeynes@103: int screen = XScreenNumberOfScreen(video_x11_screen); nkeynes@103: XVisualInfo *visual; nkeynes@103: nkeynes@103: if( glXQueryVersion( video_x11_display, &major, &minor ) == False ) { nkeynes@103: ERROR( "X Display lacks the GLX nature" ); nkeynes@103: return FALSE; nkeynes@103: } nkeynes@103: if( major < 1 || minor < 2 ) { nkeynes@103: ERROR( "X display supports GLX %d.%d, but we need at least 1.2", major, minor ); nkeynes@103: return FALSE; nkeynes@103: } nkeynes@103: nkeynes@103: /* Find ourselves a nice visual */ nkeynes@103: visual = glXChooseVisual( video_x11_display, nkeynes@103: screen, nkeynes@103: visual_attrs ); nkeynes@103: if( visual == NULL ) { nkeynes@103: ERROR( "Unable to obtain a compatible visual" ); nkeynes@103: return FALSE; nkeynes@103: } nkeynes@103: nkeynes@103: /* And a matching gl context */ nkeynes@103: glx_context = glXCreateContext( video_x11_display, visual, None, True ); nkeynes@103: if( glx_context == NULL ) { nkeynes@103: ERROR( "Unable to obtain a GLX Context. Possibly your system is broken in some small, undefineable way" ); nkeynes@103: return FALSE; nkeynes@103: } nkeynes@103: nkeynes@103: nkeynes@103: /* Ok, all good so far. Unfortunately the visual we need to use will nkeynes@103: * almost certainly be different from the one our frame is using. Which nkeynes@103: * means we have to jump through the following hoops to create a nkeynes@103: * child window with the appropriate settings. nkeynes@103: */ nkeynes@103: win_attrs.event_mask = 0; nkeynes@103: win_attrs.colormap = XCreateColormap( video_x11_display, nkeynes@103: RootWindowOfScreen(video_x11_screen), nkeynes@103: visual->visual, AllocNone ); nkeynes@103: glx_window = XCreateWindow( video_x11_display, video_x11_window, nkeynes@352: 0, 0, width, height, 0, visual->depth, nkeynes@103: InputOutput, visual->visual, nkeynes@103: CWColormap | CWEventMask, nkeynes@103: &win_attrs ); nkeynes@103: if( glx_window == None ) { nkeynes@103: /* Hrm. Aww, no window? */ nkeynes@103: ERROR( "Unable to create GLX window" ); nkeynes@103: glXDestroyContext( video_x11_display, glx_context ); nkeynes@103: if( win_attrs.colormap ) nkeynes@103: XFreeColormap( video_x11_display, win_attrs.colormap ); nkeynes@103: return FALSE; nkeynes@103: } nkeynes@103: XMapRaised( video_x11_display, glx_window ); nkeynes@103: nkeynes@103: /* And finally set the window to be the active drawing area */ nkeynes@103: if( glXMakeCurrent( video_x11_display, glx_window, glx_context ) == False ) { nkeynes@103: /* Ok you have _GOT_ to be kidding me */ nkeynes@103: ERROR( "Unable to prepare GLX window for drawing" ); nkeynes@103: XDestroyWindow( video_x11_display, glx_window ); nkeynes@103: XFreeColormap( video_x11_display, win_attrs.colormap ); nkeynes@103: glXDestroyContext( video_x11_display, glx_context ); nkeynes@103: return FALSE; nkeynes@103: } nkeynes@103: return TRUE; nkeynes@103: } nkeynes@370: nkeynes@352: void video_glx_shutdown() nkeynes@352: { nkeynes@405: if( glsl_loaded ) { nkeynes@405: glsl_unload_shaders(); nkeynes@405: } nkeynes@370: if( glx_window != None ) { nkeynes@370: XDestroyWindow( video_x11_display, glx_window ); nkeynes@370: XFreeColormap( video_x11_display, win_attrs.colormap ); nkeynes@370: glx_window = None; nkeynes@370: } nkeynes@370: if( glx_context != NULL ) { nkeynes@370: glXDestroyContext( video_x11_display, glx_context ); nkeynes@370: glx_context = NULL; nkeynes@370: } nkeynes@352: } nkeynes@352: nkeynes@103: nkeynes@108: int video_glx_load_font( const gchar *font_name ) nkeynes@108: { nkeynes@108: int lists; nkeynes@108: XFontStruct *font = XLoadQueryFont(video_x11_display, font_name ); nkeynes@108: if (font == NULL) nkeynes@108: return -1; nkeynes@108: nkeynes@108: lists = glGenLists(96); nkeynes@108: glXUseXFont(font->fid, 32, 96, lists); nkeynes@108: XFreeFont(video_x11_display, font); nkeynes@108: } nkeynes@108: nkeynes@108: nkeynes@103: void video_glx_swap_buffers( void ) nkeynes@103: { nkeynes@103: glXSwapBuffers( video_x11_display, glx_window ); nkeynes@103: } nkeynes@103: