Search
lxdream.org :: lxdream/src/drivers/video_glx.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/video_glx.c
changeset 545:fdcdcd8b9fd1
next561:533f6b478071
next586:2a3ba82cf243
author nkeynes
date Thu Nov 29 09:28:28 2007 +0000 (13 years ago)
permissions -rw-r--r--
last change Refactor GLX support and implement pbuffer rendering support
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/drivers/video_glx.c Thu Nov 29 09:28:28 2007 +0000
1.3 @@ -0,0 +1,343 @@
1.4 +/**
1.5 + * $Id: video_x11.c,v 1.20 2007-10-31 12:05:23 nkeynes Exp $
1.6 + *
1.7 + * Shared functions for all X11-based display drivers.
1.8 + *
1.9 + * Copyright (c) 2005 Nathan Keynes.
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + */
1.21 +
1.22 +#include <X11/Xlib.h>
1.23 +#include <GL/glx.h>
1.24 +#include <GL/gl.h>
1.25 +#include "dream.h"
1.26 +#include "pvr2/pvr2.h"
1.27 +#include "drivers/video_glx.h"
1.28 +#include "drivers/gl_common.h"
1.29 +
1.30 +/**
1.31 + * General X11 parameters. The front-end driver is expected to set this up
1.32 + * by calling video_glx_init after initializing itself.
1.33 + */
1.34 +Display *video_x11_display = NULL;
1.35 +Window video_x11_window = 0;
1.36 +static gboolean glsl_loaded = FALSE;
1.37 +
1.38 +static int glx_version = 100;
1.39 +static XVisualInfo *glx_visual;
1.40 +static GLXFBConfig glx_fbconfig;
1.41 +static GLXContext glx_context = NULL;
1.42 +static gboolean glx_is_initialized = FALSE;
1.43 +static gboolean glx_fbconfig_supported = FALSE;
1.44 +static gboolean glx_pbuffer_supported = FALSE;
1.45 +static int glx_pbuffer_texture = 0;
1.46 +
1.47 +/* Prototypes for pbuffer support methods */
1.48 +static void glx_pbuffer_init( display_driver_t driver );
1.49 +static render_buffer_t glx_pbuffer_create_render_buffer( uint32_t width, uint32_t height );
1.50 +static void glx_pbuffer_destroy_render_buffer( render_buffer_t buffer );
1.51 +static gboolean glx_pbuffer_set_render_target( render_buffer_t buffer );
1.52 +static gboolean glx_pbuffer_display_render_buffer( render_buffer_t buffer );
1.53 +static void glx_pbuffer_load_frame_buffer( frame_buffer_t frame, render_buffer_t buffer );
1.54 +static gboolean glx_pbuffer_display_blank( uint32_t colour );
1.55 +static gboolean glx_pbuffer_read_render_buffer( unsigned char *target, render_buffer_t buffer, int rowstride, int format );
1.56 +
1.57 +/**
1.58 + * Test if a specific extension is supported. From opengl.org
1.59 + * @param extension extension name to check for
1.60 + * @return TRUE if supported, otherwise FALSE.
1.61 + */
1.62 +gboolean isServerGLXExtensionSupported( Display *display, int screen,
1.63 + const char *extension )
1.64 +{
1.65 + const char *extensions = NULL;
1.66 + const char *start;
1.67 + char *where, *terminator;
1.68 +
1.69 + /* Extension names should not have spaces. */
1.70 + where = strchr(extension, ' ');
1.71 + if (where || *extension == '\0')
1.72 + return 0;
1.73 + extensions = glXQueryServerString(display, screen, GLX_EXTENSIONS);
1.74 + start = extensions;
1.75 + for (;;) {
1.76 + where = strstr((const char *) start, extension);
1.77 + if (!where)
1.78 + break;
1.79 + terminator = where + strlen(extension);
1.80 + if (where == start || *(where - 1) == ' ')
1.81 + if (*terminator == ' ' || *terminator == '\0')
1.82 + return TRUE;
1.83 + start = terminator;
1.84 + }
1.85 + return FALSE;
1.86 +}
1.87 +
1.88 +gboolean video_glx_init( Display *display, int screen )
1.89 +{
1.90 + int major, minor;
1.91 +
1.92 + if( glx_is_initialized ) {
1.93 + return TRUE;
1.94 + }
1.95 +
1.96 + Bool result = glXQueryVersion( display, &major, &minor );
1.97 + if( result != False ) {
1.98 + glx_version = (major*100) + minor;
1.99 + }
1.100 +
1.101 + glx_fbconfig_supported = (glx_version >= 103 ||
1.102 + isServerGLXExtensionSupported(display, screen,
1.103 + "GLX_SGIX_fbconfig") );
1.104 + glx_pbuffer_supported = (glx_version >= 103 ||
1.105 + isServerGLXExtensionSupported(display, screen,
1.106 + "GLX_SGIX_pbuffer") );
1.107 +
1.108 + if( glx_fbconfig_supported ) {
1.109 + int nelem;
1.110 + int fb_attribs[] = { GLX_DRAWABLE_TYPE,
1.111 + GLX_PBUFFER_BIT|GLX_WINDOW_BIT,
1.112 + GLX_RENDER_TYPE, GLX_RGBA_BIT,
1.113 + GLX_DEPTH_SIZE, 24, 0 };
1.114 + GLXFBConfig *configs = glXChooseFBConfig( display, screen,
1.115 + fb_attribs, &nelem );
1.116 +
1.117 + if( configs == NULL || nelem == 0 ) {
1.118 + /* Didn't work. Fallback to 1.2 methods */
1.119 + glx_fbconfig_supported = FALSE;
1.120 + glx_pbuffer_supported = FALSE;
1.121 + } else {
1.122 + glx_fbconfig = configs[0];
1.123 + glx_visual = glXGetVisualFromFBConfig(display, glx_fbconfig);
1.124 + XFree(configs);
1.125 + }
1.126 + }
1.127 +
1.128 + if( !glx_fbconfig_supported ) {
1.129 + int attribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, 0 };
1.130 + glx_visual = glXChooseVisual( display, screen, attribs );
1.131 + }
1.132 + glx_is_initialized = TRUE;
1.133 + return TRUE;
1.134 +}
1.135 +
1.136 +gboolean video_glx_init_context( Display *display, Window window )
1.137 +{
1.138 + if( glx_fbconfig_supported ) {
1.139 + glx_context = glXCreateNewContext( display, glx_fbconfig,
1.140 + GLX_RGBA_TYPE, NULL, True );
1.141 + if( glx_context == NULL ) {
1.142 + ERROR( "Unable to create a GLX Context.");
1.143 + return FALSE;
1.144 + }
1.145 +
1.146 + if( glXMakeContextCurrent( display, window, window,
1.147 + glx_context ) == False ) {
1.148 + ERROR( "Unable to prepare GLX context for drawing" );
1.149 + glXDestroyContext( display, glx_context );
1.150 + return FALSE;
1.151 + }
1.152 + } else {
1.153 + glx_context = glXCreateContext( display, glx_visual, None, True );
1.154 + if( glx_context == NULL ) {
1.155 + ERROR( "Unable to create a GLX Context.");
1.156 + return FALSE;
1.157 + }
1.158 +
1.159 + if( glXMakeCurrent( display, window, glx_context ) == False ) {
1.160 + ERROR( "Unable to prepare GLX context for drawing" );
1.161 + glXDestroyContext( display, glx_context );
1.162 + return FALSE;
1.163 + }
1.164 + }
1.165 +
1.166 + if( !glXIsDirect(display, glx_context) ) {
1.167 + WARN( "Not using direct rendering - this is likely to be slow" );
1.168 + }
1.169 +
1.170 + texcache_gl_init();
1.171 + video_x11_display = display;
1.172 + video_x11_window = window;
1.173 +
1.174 + return TRUE;
1.175 +}
1.176 +
1.177 +gboolean video_glx_init_driver( display_driver_t driver )
1.178 +{
1.179 + if( gl_fbo_is_supported() ) { // First preference
1.180 + gl_fbo_init(driver);
1.181 + } else if( glx_pbuffer_supported ) {
1.182 + glx_pbuffer_init(driver);
1.183 + } else {
1.184 + ERROR( "Unable to create render buffers (requires either EXT_framebuffer_object or GLX 1.3+)" );
1.185 + video_glx_shutdown();
1.186 + return FALSE;
1.187 + }
1.188 + return TRUE;
1.189 +}
1.190 +
1.191 +
1.192 +void video_glx_shutdown()
1.193 +{
1.194 + // texcache_gl_shutdown();
1.195 + glx_is_initialized = FALSE;
1.196 + if( glx_context != NULL ) {
1.197 + glXDestroyContext( video_x11_display, glx_context );
1.198 + glx_context = NULL;
1.199 + }
1.200 + if( glx_visual != NULL ) {
1.201 + XFree(glx_visual);
1.202 + glx_visual = NULL;
1.203 + }
1.204 +}
1.205 +
1.206 +
1.207 +XVisualInfo *video_glx_get_visual()
1.208 +{
1.209 + return glx_visual;
1.210 +}
1.211 +
1.212 +
1.213 +int video_glx_load_font( const gchar *font_name )
1.214 +{
1.215 + int lists;
1.216 + XFontStruct *font = XLoadQueryFont(video_x11_display, font_name );
1.217 + if (font == NULL)
1.218 + return -1;
1.219 +
1.220 + lists = glGenLists(96);
1.221 + glXUseXFont(font->fid, 32, 96, lists);
1.222 + XFreeFont(video_x11_display, font);
1.223 + return lists;
1.224 +}
1.225 +
1.226 +
1.227 +void video_glx_swap_buffers( void )
1.228 +{
1.229 + glXSwapBuffers( video_x11_display, video_x11_window );
1.230 +}
1.231 +
1.232 +void video_glx_make_window_current( void )
1.233 +{
1.234 + glXMakeCurrent( video_x11_display, video_x11_window, glx_context );
1.235 +}
1.236 +
1.237 +
1.238 +// Pbuffer support
1.239 +
1.240 +/**
1.241 + * Construct the initial frame buffers and allocate ids for everything.
1.242 + * The render handling driver methods are set to the fbo versions.
1.243 + */
1.244 +static void glx_pbuffer_init( display_driver_t driver )
1.245 +{
1.246 + glGenTextures( 1, &glx_pbuffer_texture );
1.247 + driver->create_render_buffer = glx_pbuffer_create_render_buffer;
1.248 + driver->destroy_render_buffer = glx_pbuffer_destroy_render_buffer;
1.249 + driver->set_render_target = glx_pbuffer_set_render_target;
1.250 + driver->display_render_buffer = glx_pbuffer_display_render_buffer;
1.251 + driver->load_frame_buffer = glx_pbuffer_load_frame_buffer;
1.252 + driver->display_blank = glx_pbuffer_display_blank;
1.253 + driver->read_render_buffer = glx_pbuffer_read_render_buffer;
1.254 +}
1.255 +
1.256 +void glx_pbuffer_shutdown()
1.257 +{
1.258 + glDeleteTextures( 1, &glx_pbuffer_texture );
1.259 +}
1.260 +
1.261 +static render_buffer_t glx_pbuffer_create_render_buffer( uint32_t width, uint32_t height )
1.262 +{
1.263 + int attribs[] = { GLX_PBUFFER_WIDTH, width, GLX_PBUFFER_HEIGHT, height,
1.264 + GLX_PRESERVED_CONTENTS, True, 0 };
1.265 + GLXPbuffer pb = glXCreatePbuffer( video_x11_display, glx_fbconfig, attribs );
1.266 + if( pb == (GLXPbuffer)NULL ) {
1.267 + ERROR( "Unable to create pbuffer" );
1.268 + return NULL;
1.269 + }
1.270 + render_buffer_t buffer = calloc( sizeof(struct render_buffer), 1 );
1.271 + buffer->width = width;
1.272 + buffer->height = height;
1.273 + buffer->buf_id = pb;
1.274 + return buffer;
1.275 +}
1.276 +
1.277 +static void glx_pbuffer_destroy_render_buffer( render_buffer_t buffer )
1.278 +{
1.279 + glXDestroyPbuffer( video_x11_display, (GLXPbuffer)buffer->buf_id );
1.280 + buffer->buf_id = 0;
1.281 + free( buffer );
1.282 +}
1.283 +
1.284 +static gboolean glx_pbuffer_set_render_target( render_buffer_t buffer )
1.285 +{
1.286 + glFinish();
1.287 + if( glXMakeContextCurrent( video_x11_display, (GLXPbuffer)buffer->buf_id, (GLXPbuffer)buffer->buf_id, glx_context ) == False ) {
1.288 + ERROR( "Make context current (pbuffer) failed!" );
1.289 + }
1.290 + /* setup the gl context */
1.291 + glViewport( 0, 0, buffer->width, buffer->height );
1.292 + glDrawBuffer(GL_FRONT);
1.293 +
1.294 + return TRUE;
1.295 +}
1.296 +
1.297 +/**
1.298 + * Render the texture holding the given buffer to the front window
1.299 + * buffer.
1.300 + */
1.301 +static gboolean glx_pbuffer_display_render_buffer( render_buffer_t buffer )
1.302 +{
1.303 + glFinish();
1.304 + glReadBuffer( GL_FRONT );
1.305 + glDrawBuffer( GL_FRONT );
1.306 + glXMakeContextCurrent( video_x11_display, (GLXPbuffer)buffer->buf_id, (GLXPbuffer)buffer->buf_id, glx_context );
1.307 + glBindTexture( GL_TEXTURE_RECTANGLE_ARB, glx_pbuffer_texture );
1.308 + glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, buffer->width, buffer->height, 0 );
1.309 + video_glx_make_window_current();
1.310 + gl_texture_window( buffer->width, buffer->height, glx_pbuffer_texture, buffer->inverted );
1.311 + return TRUE;
1.312 +}
1.313 +
1.314 +static void glx_pbuffer_load_frame_buffer( frame_buffer_t frame, render_buffer_t buffer )
1.315 +{
1.316 + glFinish();
1.317 + glXMakeContextCurrent( video_x11_display, (GLXPbuffer)buffer->buf_id, (GLXPbuffer)buffer->buf_id, glx_context );
1.318 + GLenum type = colour_formats[frame->colour_format].type;
1.319 + GLenum format = colour_formats[frame->colour_format].format;
1.320 + int bpp = colour_formats[frame->colour_format].bpp;
1.321 + int rowstride = (frame->rowstride / bpp) - frame->width;
1.322 +
1.323 + gl_reset_state();
1.324 + glPixelStorei( GL_UNPACK_ROW_LENGTH, rowstride );
1.325 + glRasterPos2f(0.375, frame->height-0.375);
1.326 + glPixelZoom( 1.0, 1.0 );
1.327 + glDrawPixels( frame->width, frame->height, format, type, frame->data );
1.328 + glFlush();
1.329 +}
1.330 +
1.331 +static gboolean glx_pbuffer_display_blank( uint32_t colour )
1.332 +{
1.333 + glFinish();
1.334 + video_glx_make_window_current();
1.335 + return gl_display_blank( colour );
1.336 +}
1.337 +
1.338 +static gboolean glx_pbuffer_read_render_buffer( unsigned char *target, render_buffer_t buffer,
1.339 + int rowstride, int format )
1.340 +{
1.341 + glXMakeCurrent( video_x11_display, (GLXDrawable)buffer->buf_id, glx_context );
1.342 + glReadBuffer( GL_FRONT );
1.343 + return gl_read_render_buffer( target, buffer, rowstride, format );
1.344 +}
1.345 +
1.346 +
.