more robust handling of glx version and extension functions w.r.t. pbuffers and pixmaps

This commit is contained in:
David Rose 2010-03-08 20:58:06 +00:00
parent 30dddab983
commit 4fd129413a
14 changed files with 493 additions and 233 deletions

View File

@ -408,8 +408,8 @@ make_output(GraphicsPipe *pipe,
<< " got: " << window->get_fb_properties() << "\n";
}
} else {
display_cat.error()
<< "Window wouldn't open; abandoning window.\n";
display_cat.info()
<< window->get_type() << " wouldn't open; abandoning.\n";
}
// No good; delete the window and keep trying.

View File

@ -20,7 +20,7 @@
glxGraphicsWindow.h glxGraphicsWindow.cxx \
glxGraphicsStateGuardian.h glxGraphicsStateGuardian.I \
glxGraphicsStateGuardian.cxx \
glxext.h
panda_glxext.h
#define INSTALL_HEADERS \
glxGraphicsBuffer.I glxGraphicsBuffer.h \

View File

@ -16,6 +16,7 @@
#include "glxGraphicsBuffer.h"
#include "glxGraphicsPipe.h"
#include "glxGraphicsPixmap.h"
#include "glxGraphicsBuffer.h"
#include "glxGraphicsWindow.h"
#include "glxGraphicsStateGuardian.h"
#include "graphicsPipeSelection.h"
@ -43,6 +44,19 @@ ConfigVariableBool glx_get_os_address
"addresses of extension functions. This will be done only "
"if glxGetProcAddress() cannot be used for some reason."));
ConfigVariableBool gl_support_fbo
("gl-support-fbo", true,
PRC_DESC("Configure this false if your GL's implementation of "
"EXT_framebuffer_object is broken. The system might still be "
"able to create buffers using pbuffers or the like."));
ConfigVariableBool glx_support_fbconfig
("glx-support-fbconfig", true,
PRC_DESC("Set this true to enable the use of the advanced FBConfig "
"interface (as opposed to the older XVisual interface) "
"if it is available, to select a graphics visual and "
"create an OpenGL context."));
ConfigVariableBool glx_support_pbuffer
("glx-support-pbuffer", true,
PRC_DESC("Set this true to enable the use of X pbuffer-based offscreen "
@ -53,9 +67,7 @@ ConfigVariableBool glx_support_pixmap
("glx-support-pixmap", false,
PRC_DESC("Set this true to enable the use of X pixmap-based offscreen "
"buffers. This is false by default because pixmap-based buffers "
"are usually slower than pbuffer-based buffers, and because at "
"least one driver is known to crash (crash!) when it attempts "
"to create a pixmap-based buffer."));
"are usually slower than pbuffer-based buffers."));
////////////////////////////////////////////////////////////////////
@ -79,6 +91,7 @@ init_libglxdisplay() {
#endif // HAVE_GLXFBCONFIG
glxGraphicsPipe::init_type();
glxGraphicsPixmap::init_type();
glxGraphicsBuffer::init_type();
glxGraphicsWindow::init_type();
glxGraphicsStateGuardian::init_type();

View File

@ -28,6 +28,8 @@ extern EXPCL_PANDAGL void init_libglxdisplay();
extern ConfigVariableBool glx_get_proc_address;
extern ConfigVariableBool glx_get_os_address;
extern ConfigVariableBool gl_support_fbo;
extern ConfigVariableBool glx_support_fbconfig;
extern ConfigVariableBool glx_support_pbuffer;
extern ConfigVariableBool glx_support_pixmap;

View File

@ -21,10 +21,6 @@
#include "glgsg.h"
#include "pStatTimer.h"
#ifdef HAVE_GLXFBCONFIG
// This whole class doesn't make sense unless we have the GLXFBConfig
// and associated GLXPbuffer interfaces available.
TypeHandle glxGraphicsBuffer::_type_handle;
////////////////////////////////////////////////////////////////////
@ -76,7 +72,8 @@ begin_frame(FrameMode mode, Thread *current_thread) {
PStatTimer timer(_make_current_pcollector, current_thread);
begin_frame_spam(mode);
if (_gsg == (GraphicsStateGuardian *)NULL) {
if (_gsg == (GraphicsStateGuardian *)NULL ||
_pbuffer == None) {
return false;
}
@ -140,15 +137,19 @@ void glxGraphicsBuffer::
close_buffer() {
if (_gsg != (GraphicsStateGuardian *)NULL) {
glXMakeCurrent(_display, None, NULL);
if (_pbuffer != None) {
glxGraphicsStateGuardian *glxgsg;
DCAST_INTO_V(glxgsg, _gsg);
glxgsg->_glXDestroyPbuffer(_display, _pbuffer);
_pbuffer = None;
}
_gsg.clear();
_active = false;
}
if (_pbuffer != None) {
glXDestroyPbuffer(_display, _pbuffer);
_pbuffer = None;
}
_pbuffer = None;
_is_valid = false;
}
@ -175,43 +176,47 @@ open_buffer() {
// If the old gsg has the wrong pixel format, create a
// new one that shares with the old gsg.
DCAST_INTO_R(glxgsg, _gsg, false);
if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) {
if (!glxgsg->_context_has_pbuffer ||
!glxgsg->get_fb_properties().subsumes(_fb_properties)) {
// We need a new pixel format, and hence a new GSG.
glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true, false);
_gsg = glxgsg;
}
}
if (glxgsg->_fbconfig == None) {
// If we didn't use an fbconfig to create the GSG, we can't create
// a PBuffer.
if (glxgsg->_fbconfig == None || glxgsg->_context_has_pbuffer) {
// If we didn't use an fbconfig to create the GSG, or it doesn't
// support buffers, we can't create a PBuffer.
return false;
}
nassertr(glxgsg->_supports_pbuffer, false);
static const int max_attrib_list = 32;
int attrib_list[max_attrib_list];
int n=0;
int n = 0;
#ifdef HAVE_OFFICIAL_GLXFBCONFIG
// The official GLX 1.3 version passes in the size in the attrib
// list.
attrib_list[n++] = GLX_PBUFFER_WIDTH;
attrib_list[n++] = _x_size;
attrib_list[n++] = GLX_PBUFFER_HEIGHT;
attrib_list[n++] = _y_size;
nassertr(n < max_attrib_list, false);
attrib_list[n] = (int)None;
_pbuffer = glXCreatePbuffer(glxgsg->_display, glxgsg->_fbconfig,
attrib_list);
#else
// The SGI version passed in the size in the parameter list.
nassertr(n < max_attrib_list, false);
attrib_list[n] = (int)None;
_pbuffer = glXCreateGLXPbufferSGIX(glxgsg->_display, glxgsg->_fbconfig,
_x_size, _y_size, attrib_list);
#endif
if (glxgsg->_uses_sgix_pbuffer) {
// The SGI version passed in the size in the parameter list.
nassertr(n < max_attrib_list, false);
attrib_list[n] = (int)None;
_pbuffer = glxgsg->_glXCreateGLXPbufferSGIX(glxgsg->_display, glxgsg->_fbconfig,
_x_size, _y_size, attrib_list);
} else {
// The official GLX 1.3 version passes in the size in the attrib
// list.
attrib_list[n++] = GLX_PBUFFER_WIDTH;
attrib_list[n++] = _x_size;
attrib_list[n++] = GLX_PBUFFER_HEIGHT;
attrib_list[n++] = _y_size;
nassertr(n < max_attrib_list, false);
attrib_list[n] = (int)None;
_pbuffer = glxgsg->_glXCreatePbuffer(glxgsg->_display, glxgsg->_fbconfig,
attrib_list);
}
if (_pbuffer == None) {
glxdisplay_cat.error()
@ -235,6 +240,3 @@ open_buffer() {
_is_valid = true;
return true;
}
#endif // HAVE_GLXFBCONFIG

View File

@ -20,10 +20,6 @@
#include "glxGraphicsPipe.h"
#include "graphicsBuffer.h"
#ifdef HAVE_GLXFBCONFIG
// This whole class doesn't make sense unless we have the GLXFBConfig
// and associated GLXPbuffer interfaces available.
////////////////////////////////////////////////////////////////////
// Class : glxGraphicsBuffer
// Description : An offscreen buffer in the GLX environment. This
@ -71,6 +67,4 @@ private:
#include "glxGraphicsBuffer.I"
#endif // HAVE_GLXFBCONFIG
#endif

View File

@ -119,7 +119,7 @@ make_output(const string &name,
if (retry == 1) {
if ((host==0)||
// (!gl_support_fbo)||
(!gl_support_fbo)||
((flags&BF_require_parasite)!=0)||
((flags&BF_require_window)!=0)) {
return NULL;
@ -152,34 +152,33 @@ make_output(const string &name,
flags, gsg, host);
}
#ifdef HAVE_GLXFBCONFIG
// Third thing to try: a glxGraphicsBuffer
if (retry == 2) {
if (!glx_support_pbuffer) {
return NULL;
}
if (((flags&BF_require_parasite)!=0)||
((flags&BF_require_window)!=0)||
((flags&BF_resizeable)!=0)||
((flags&BF_size_track_host)!=0)) {
return NULL;
}
if (!support_rtt) {
if (((flags&BF_rtt_cumulative)!=0)||
((flags&BF_can_bind_every)!=0)) {
// If we require Render-to-Texture, but can't be sure we
// support it, bail.
if (glxgsg == NULL || glxgsg->_supports_fbconfig) {
if (retry == 2) {
if (!glx_support_pbuffer) {
return NULL;
}
if (((flags&BF_require_parasite)!=0)||
((flags&BF_require_window)!=0)||
((flags&BF_resizeable)!=0)||
((flags&BF_size_track_host)!=0)) {
return NULL;
}
if (!support_rtt) {
if (((flags&BF_rtt_cumulative)!=0)||
((flags&BF_can_bind_every)!=0)) {
// If we require Render-to-Texture, but can't be sure we
// support it, bail.
return NULL;
}
}
return new glxGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
return new glxGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
#endif // HAVE_GLXFBCONFIG
// Third thing to try: a glxGraphicsPixmap.
if (retry == 3) {

View File

@ -27,20 +27,25 @@ class FrameBufferProperties;
#ifndef CPPPARSER
// Don't pick up the system glxext.h; use our own, which is better.
#define __glxext_h_
#include <GL/glx.h>
/*
#if defined(GLX_VERSION_1_3)
// If the system glx version is at least 1.3, then we know we have
// GLXFBConfig and GLXPbuffer.
#define HAVE_GLXFBCONFIG
#define HAVE_OFFICIAL_GLXFBCONFIG
#endif
*/
// This must be included after we have included glgsg.h (which
// includes gl.h), and after we have checked GLX_VERSION_1_3. But we
// must also include it before we redefine the GLXFBConfig types,
// below.
#include "glxext.h"
#include "panda_glxext.h"
// drose: the version of GL/glx.h that ships with Fedora Core 2 seems
// to define GLX_VERSION_1_4, but for some reason does not define
@ -54,6 +59,7 @@ class FrameBufferProperties;
#endif
/*
#if !defined(HAVE_GLXFBCONFIG) && defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
// If the system glx version isn't 1.3, but these were defined as
// extensions, we can work with that.
@ -68,6 +74,7 @@ class FrameBufferProperties;
#define HAVE_GLXFBCONFIG
#define HAVE_SGI_GLXFBCONFIG
#endif
*/
#endif // CPPPARSER

View File

@ -75,7 +75,8 @@ begin_frame(FrameMode mode, Thread *current_thread) {
PStatTimer timer(_make_current_pcollector, current_thread);
begin_frame_spam(mode);
if (_gsg == (GraphicsStateGuardian *)NULL) {
if (_gsg == (GraphicsStateGuardian *)NULL ||
_glx_pixmap == None) {
return false;
}
@ -179,13 +180,19 @@ open_buffer() {
// If the old gsg has the wrong pixel format, create a
// new one that shares with the old gsg.
DCAST_INTO_R(glxgsg, _gsg, false);
if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) {
if (!glxgsg->_context_has_pixmap ||
!glxgsg->get_fb_properties().subsumes(_fb_properties)) {
glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
_gsg = glxgsg;
}
}
if (!glxgsg->_context_has_pixmap) {
// Hmm, the GSG we created won't work.
return false;
}
XVisualInfo *visual_info = glxgsg->_visual;
if (visual_info == NULL) {
// No X visual for this fbconfig; how can we create the pixmap?
@ -214,16 +221,13 @@ open_buffer() {
return false;
}
#ifdef HAVE_GLXFBCONFIG
if (glxgsg->_fbconfig) {
// Use the FBConfig to create the pixmap.
_glx_pixmap = glXCreatePixmap(_display, glxgsg->_fbconfig, _x_pixmap, NULL);
} else
#endif // HAVE_GLXFBCONFIG
{
// Use the XVisual to create the pixmap.
_glx_pixmap = glXCreateGLXPixmap(_display, visual_info, _x_pixmap);
}
_glx_pixmap = glxgsg->_glXCreatePixmap(_display, glxgsg->_fbconfig, _x_pixmap, NULL);
} else {
// Use the XVisual to create the pixmap.
_glx_pixmap = glXCreateGLXPixmap(_display, visual_info, _x_pixmap);
}
if (_glx_pixmap == None) {
glxdisplay_cat.error()

View File

@ -39,6 +39,14 @@ glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
_visual=0;
_visuals=0;
_fbconfig=0;
_context_has_pbuffer = false;
_context_has_pixmap = false;
_slow = false;
_supports_swap_control = false;
_supports_fbconfig = false;
_supports_pbuffer = false;
_uses_sgix_pbuffer = false;
if (share_with != (glxGraphicsStateGuardian *)NULL) {
_prepared_objects = share_with->get_prepared_objects();
@ -48,6 +56,7 @@ glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
_libgl_handle = NULL;
_checked_get_proc_address = false;
_glXGetProcAddress = NULL;
_temp_xwindow = (Window)NULL;
}
////////////////////////////////////////////////////////////////////
@ -57,6 +66,7 @@ glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
////////////////////////////////////////////////////////////////////
glxGraphicsStateGuardian::
~glxGraphicsStateGuardian() {
destroy_temp_xwindow();
if (_visuals != (XVisualInfo *)NULL) {
XFree(_visuals);
}
@ -71,7 +81,7 @@ glxGraphicsStateGuardian::
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsStateGuardian::get_properties
// Access: Private
// Access: Public
// Description: Gets the FrameBufferProperties to match the
// indicated visual.
////////////////////////////////////////////////////////////////////
@ -131,87 +141,86 @@ get_properties(FrameBufferProperties &properties, XVisualInfo *visual) {
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsStateGuardian::get_properties_advanced
// Access: Private
// Access: Public
// Description: Gets the FrameBufferProperties to match the
// indicated GLXFBConfig
////////////////////////////////////////////////////////////////////
void glxGraphicsStateGuardian::
get_properties_advanced(FrameBufferProperties &properties,
bool &pbuffer_supported, bool &pixmap_supported,
bool &slow, fbconfig config) {
bool &context_has_pbuffer, bool &context_has_pixmap,
bool &slow, GLXFBConfig config) {
properties.clear();
#ifdef HAVE_GLXFBCONFIG
// Now update our framebuffer_mode and bit depth appropriately.
int render_mode, double_buffer, stereo, red_size, green_size, blue_size,
alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
depth_size, stencil_size, samples, drawable_type, caveat;
glXGetFBConfigAttrib(_display, config, GLX_RGBA, &render_mode);
glXGetFBConfigAttrib(_display, config, GLX_DOUBLEBUFFER, &double_buffer);
glXGetFBConfigAttrib(_display, config, GLX_STEREO, &stereo);
glXGetFBConfigAttrib(_display, config, GLX_RED_SIZE, &red_size);
glXGetFBConfigAttrib(_display, config, GLX_GREEN_SIZE, &green_size);
glXGetFBConfigAttrib(_display, config, GLX_BLUE_SIZE, &blue_size);
glXGetFBConfigAttrib(_display, config, GLX_ALPHA_SIZE, &alpha_size);
glXGetFBConfigAttrib(_display, config, GLX_ACCUM_RED_SIZE, &ared_size);
glXGetFBConfigAttrib(_display, config, GLX_ACCUM_GREEN_SIZE, &agreen_size);
glXGetFBConfigAttrib(_display, config, GLX_ACCUM_BLUE_SIZE, &ablue_size);
glXGetFBConfigAttrib(_display, config, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
glXGetFBConfigAttrib(_display, config, GLX_DEPTH_SIZE, &depth_size);
glXGetFBConfigAttrib(_display, config, GLX_STENCIL_SIZE, &stencil_size);
glXGetFBConfigAttrib(_display, config, GLX_SAMPLES, &samples);
glXGetFBConfigAttrib(_display, config, GLX_DRAWABLE_TYPE, &drawable_type);
glXGetFBConfigAttrib(_display, config, GLX_CONFIG_CAVEAT, &caveat);
pbuffer_supported = false;
if ((drawable_type & GLX_PBUFFER_BIT)!=0) {
pbuffer_supported = true;
if (_supports_fbconfig) {
// Now update our framebuffer_mode and bit depth appropriately.
int render_mode, double_buffer, stereo, red_size, green_size, blue_size,
alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
depth_size, stencil_size, samples, drawable_type, caveat;
_glXGetFBConfigAttrib(_display, config, GLX_RGBA, &render_mode);
_glXGetFBConfigAttrib(_display, config, GLX_DOUBLEBUFFER, &double_buffer);
_glXGetFBConfigAttrib(_display, config, GLX_STEREO, &stereo);
_glXGetFBConfigAttrib(_display, config, GLX_RED_SIZE, &red_size);
_glXGetFBConfigAttrib(_display, config, GLX_GREEN_SIZE, &green_size);
_glXGetFBConfigAttrib(_display, config, GLX_BLUE_SIZE, &blue_size);
_glXGetFBConfigAttrib(_display, config, GLX_ALPHA_SIZE, &alpha_size);
_glXGetFBConfigAttrib(_display, config, GLX_ACCUM_RED_SIZE, &ared_size);
_glXGetFBConfigAttrib(_display, config, GLX_ACCUM_GREEN_SIZE, &agreen_size);
_glXGetFBConfigAttrib(_display, config, GLX_ACCUM_BLUE_SIZE, &ablue_size);
_glXGetFBConfigAttrib(_display, config, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
_glXGetFBConfigAttrib(_display, config, GLX_DEPTH_SIZE, &depth_size);
_glXGetFBConfigAttrib(_display, config, GLX_STENCIL_SIZE, &stencil_size);
_glXGetFBConfigAttrib(_display, config, GLX_SAMPLES, &samples);
_glXGetFBConfigAttrib(_display, config, GLX_DRAWABLE_TYPE, &drawable_type);
_glXGetFBConfigAttrib(_display, config, GLX_CONFIG_CAVEAT, &caveat);
context_has_pbuffer = false;
if ((drawable_type & GLX_PBUFFER_BIT)!=0) {
context_has_pbuffer = true;
}
context_has_pixmap = false;
if ((drawable_type & GLX_PIXMAP_BIT)!=0) {
context_has_pixmap = true;
}
slow = false;
if (caveat == GLX_SLOW_CONFIG) {
slow = true;
}
if ((drawable_type & GLX_WINDOW_BIT)==0) {
// We insist on having a context that will support an onscreen window.
return;
}
if (double_buffer) {
properties.set_back_buffers(1);
}
if (stereo) {
properties.set_stereo(1);
}
if (render_mode) {
properties.set_rgb_color(1);
} else {
properties.set_indexed_color(1);
}
properties.set_color_bits(red_size+green_size+blue_size);
properties.set_stencil_bits(stencil_size);
properties.set_depth_bits(depth_size);
properties.set_alpha_bits(alpha_size);
properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size);
properties.set_multisamples(samples);
// Set both hardware and software bits, indicating not-yet-known.
properties.set_force_software(1);
properties.set_force_hardware(1);
}
pixmap_supported = false;
if ((drawable_type & GLX_PIXMAP_BIT)!=0) {
pixmap_supported = true;
}
slow = false;
if (caveat == GLX_SLOW_CONFIG) {
slow = true;
}
if ((drawable_type & GLX_WINDOW_BIT)==0) {
// We insist on having a context that will support an onscreen window.
return;
}
if (double_buffer) {
properties.set_back_buffers(1);
}
if (stereo) {
properties.set_stereo(1);
}
if (render_mode) {
properties.set_rgb_color(1);
} else {
properties.set_indexed_color(1);
}
properties.set_color_bits(red_size+green_size+blue_size);
properties.set_stencil_bits(stencil_size);
properties.set_depth_bits(depth_size);
properties.set_alpha_bits(alpha_size);
properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size);
properties.set_multisamples(samples);
// Set both hardware and software bits, indicating not-yet-known.
properties.set_force_software(1);
properties.set_force_hardware(1);
#endif // HAVE_GLXFBCONFIG
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsStateGuardian::choose_pixel_format
// Access: Private
// Access: Public
// Description: Selects a visual or fbconfig for all the windows
// and buffers that use this gsg. Also creates the GL
// context and obtains the visual.
@ -229,8 +238,51 @@ choose_pixel_format(const FrameBufferProperties &properties,
_visuals = 0;
_fbprops.clear();
#ifdef HAVE_GLXFBCONFIG
//// Choose best format available using GLXFBConfig
// First, attempt to create a context using the XVisual interface.
// We need this before we can query the FBConfig interface, because
// we need an OpenGL context to get the required extension function
// pointers.
choose_visual(properties);
if (_context == NULL) {
// No good.
return;
}
// Now we have to initialize the context so we can query its
// capabilities and extensions. This also means creating a
// temporary window, so we have something to bind the context to and
// make it current.
init_temp_context();
if (!_supports_fbconfig) {
// We have a good OpenGL context, but it doesn't support the
// FBConfig interface, so we'll stop there.
if (glxdisplay_cat.is_debug()) {
glxdisplay_cat.debug()
<<" No FBConfig supported; using XVisual only.\n";
glxdisplay_cat.debug()
<< _fbprops << "\n";
// By convention, every indirect XVisual that can render to a
// window can also render to a GLXPixmap. Direct visuals we're
// not as sure about.
_context_has_pixmap = !glXIsDirect(_display, _context);
// Pbuffers aren't supported at all with the XVisual interface.
_context_has_pbuffer = false;
}
return;
}
// The OpenGL context supports the FBConfig interface, so we can use
// that more advanced interface to choose the actual window format
// we'll use. FBConfig provides for more options than the older
// XVisual interface, so we'd much rather use it if it's available.
int best_quality = 0;
int best_result = 0;
FrameBufferProperties best_props;
static const int max_attrib_list = 32;
int attrib_list[max_attrib_list];
@ -242,35 +294,38 @@ choose_pixel_format(const FrameBufferProperties &properties,
attrib_list[n++] = GLX_DRAWABLE_TYPE;
attrib_list[n++] = GLX_DONT_CARE;
attrib_list[n] = (int)None;
int num_configs = 0;
GLXFBConfig *configs =
glXChooseFBConfig(_display, _screen, attrib_list, &num_configs);
_glXChooseFBConfig(_display, _screen, attrib_list, &num_configs);
int best_quality = 0;
int best_result = 0;
FrameBufferProperties best_props;
// Now that we're done querying the first context, we don't need it
// anymore. Clear it so we can create our actual OpenGL context.
glXDestroyContext(_display, _context);
_context = (GLXContext)NULL;
destroy_temp_xwindow();
if (configs != 0) {
for (int i = 0; i < num_configs; ++i) {
FrameBufferProperties fbprops;
bool pbuffer_supported, pixmap_supported, slow;
get_properties_advanced(fbprops, pbuffer_supported, pixmap_supported,
bool context_has_pbuffer, context_has_pixmap, slow;
get_properties_advanced(fbprops, context_has_pbuffer, context_has_pixmap,
slow, configs[i]);
// We're not protecting this code by an is_debug() check, because if we do,
// some weird compiler bug appears and somehow makes the quality always 0.
const char *pbuffertext = pbuffer_supported ? " (pbuffer)" : "";
const char *pixmaptext = pixmap_supported ? " (pixmap)" : "";
// We're not protecting this code by an is_debug() check,
// because if we do, some weird compiler bug appears and somehow
// makes the quality always 0.
const char *pbuffertext = context_has_pbuffer ? " (pbuffer)" : "";
const char *pixmaptext = context_has_pixmap ? " (pixmap)" : "";
const char *slowtext = slow ? " (slow)" : "";
glxdisplay_cat.debug()
<< i << ": " << fbprops << pbuffertext << pixmaptext << slowtext << "\n";
int quality = fbprops.get_quality(properties);
if ((quality > 0)&&(slow)) quality -= 10000000;
if (need_pbuffer && !pbuffer_supported) {
if (need_pbuffer && !context_has_pbuffer) {
continue;
}
if (need_pixmap && !pixmap_supported) {
if (need_pixmap && !context_has_pixmap) {
continue;
}
@ -281,17 +336,31 @@ choose_pixel_format(const FrameBufferProperties &properties,
}
}
}
if (best_quality > 0) {
_fbconfig = configs[best_result];
_context =
glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context,
GL_TRUE);
_glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context,
GL_TRUE);
if (_context) {
_visuals = glXGetVisualFromFBConfig(_display, _fbconfig);
_visuals = _glXGetVisualFromFBConfig(_display, _fbconfig);
_visual = _visuals;
if (_visual) {
_fbprops = best_props;
get_properties_advanced(_fbprops, _context_has_pbuffer, _context_has_pixmap,
_slow, _fbconfig);
// hack?
//init_temp_context();
if (glxdisplay_cat.is_debug()) {
glxdisplay_cat.debug()
<< "Selected context " << best_result << "\n";
glxdisplay_cat.debug()
<< "context_has_pbuffer = " << _context_has_pbuffer
<< ", context_has_pixmap = " << _context_has_pixmap << "\n";
}
return;
}
}
@ -303,40 +372,9 @@ choose_pixel_format(const FrameBufferProperties &properties,
_visual = 0;
_visuals = 0;
}
#endif // HAVE_GLXFBCONFIG
if (need_pbuffer) {
// The xvisual interface cannot create pbuffers.
return;
}
// Scan available visuals.
int nvisuals=0;
_visuals = XGetVisualInfo(_display, 0, 0, &nvisuals);
if (_visuals != 0) {
for (int i=0; i<nvisuals; i++) {
FrameBufferProperties fbprops;
get_properties(fbprops, _visuals+i);
int quality = fbprops.get_quality(properties);
if (quality > best_quality) {
best_quality = quality;
best_result = i;
best_props = fbprops;
}
}
}
if (best_quality > 0) {
_visual = _visuals+best_result;
_context = glXCreateContext(_display, _visual, None, GL_TRUE);
if (_context) {
_fbprops = best_props;
return;
}
}
glxdisplay_cat.error() <<
"Could not find a usable pixel format.\n";
glxdisplay_cat.info()
<< "No suitable FBConfig contexts available.\n";
}
////////////////////////////////////////////////////////////////////
@ -367,6 +405,108 @@ reset() {
_glXSwapIntervalSGI(sync_video ? 1 : 0);
}
if (glx_support_fbconfig) {
if (glx_is_at_least_version(1, 3)) {
// If we have glx 1.3 or better, we have the FBConfig interface.
_supports_fbconfig = true;
_glXChooseFBConfig =
(PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfig");
_glXCreateNewContext =
(PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateNewContext");
_glXGetVisualFromFBConfig =
(PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfig");
_glXGetFBConfigAttrib =
(PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttrib");
_glXCreatePixmap =
(PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreatePixmap");
if (_glXChooseFBConfig == NULL ||
_glXCreateNewContext == NULL ||
_glXGetVisualFromFBConfig == NULL ||
_glXGetFBConfigAttrib == NULL ||
_glXCreatePixmap == NULL) {
glxdisplay_cat.error()
<< "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n";
_supports_fbconfig = false;
}
} else if (has_extension("GLX_SGIX_fbconfig")) {
// Or maybe we have the old SGIX extension for FBConfig. This is
// the same, but the function names are different--we just remap
// them to the same function pointers.
_supports_fbconfig = true;
_glXChooseFBConfig =
(PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfigSGIX");
_glXCreateNewContext =
(PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateContextWithConfigSGIX");
_glXGetVisualFromFBConfig =
(PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfigSGIX");
_glXGetFBConfigAttrib =
(PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttribSGIX");
_glXCreatePixmap =
(PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreateGLXPixmapWithConfigSGIX");
if (_glXChooseFBConfig == NULL ||
_glXCreateNewContext == NULL ||
_glXGetVisualFromFBConfig == NULL ||
_glXGetFBConfigAttrib == NULL ||
_glXCreatePixmap == NULL) {
glxdisplay_cat.error()
<< "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n";
_supports_fbconfig = false;
}
}
if (glx_is_at_least_version(1, 3)) {
// If we have glx 1.3 or better, we have the PBuffer interface.
_supports_pbuffer = true;
_uses_sgix_pbuffer = false;
_glXCreatePbuffer =
(PFNGLXCREATEPBUFFERPROC)get_extension_func("glX", "CreatePbuffer");
_glXCreateGLXPbufferSGIX = NULL;
_glXDestroyPbuffer =
(PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyPbuffer");
if (_glXCreatePbuffer == NULL ||
_glXDestroyPbuffer == NULL) {
glxdisplay_cat.error()
<< "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n";
_supports_pbuffer = false;
}
} else if (has_extension("GLX_SGIX_pbuffer")) {
// Or maybe we have the old SGIX extension for PBuffers.
_uses_sgix_pbuffer = true;
// CreatePbuffer has a different form between SGIX and 1.3,
// however, so we must treat it specially. But we can use the
// same function pointer for DestroyPbuffer.
_glXCreatePbuffer = NULL;
_glXCreateGLXPbufferSGIX =
(PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glX", "CreateGLXPbufferSGIX");
_glXDestroyPbuffer =
(PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyGLXPbufferSGIX");
if (_glXCreateGLXPbufferSGIX == NULL ||
_glXDestroyPbuffer == NULL) {
glxdisplay_cat.error()
<< "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n";
_supports_pbuffer = false;
}
}
}
if (glxdisplay_cat.is_debug()) {
glxdisplay_cat.debug()
<< "supports_swap_control = " << _supports_swap_control << "\n";
glxdisplay_cat.debug()
<< "supports_fbconfig = " << _supports_fbconfig << "\n";
glxdisplay_cat.debug()
<< "supports_pbuffer = " << _supports_pbuffer
<< " sgix = " << _uses_sgix_pbuffer << "\n";
}
// If "Mesa" is present, assume software. However, if "Mesa DRI" is
// found, it's actually a Mesa-based OpenGL layer running over a
// hardware driver.
@ -604,3 +744,90 @@ show_glx_server_string(const string &name, int id) {
}
}
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsStateGuardian::choose_visual
// Access: Private
// Description: Selects a visual for this gsg. This may be called
// initially, to create the first context needed in
// order to create the fbconfig. On successful return,
// _visual and _context will be filled in with a
// non-NULL value.
////////////////////////////////////////////////////////////////////
void glxGraphicsStateGuardian::
choose_visual(const FrameBufferProperties &properties) {
int best_quality = 0;
int best_result = 0;
FrameBufferProperties best_props;
// Scan available visuals.
int nvisuals = 0;
_visuals = XGetVisualInfo(_display, 0, 0, &nvisuals);
if (_visuals != 0) {
for (int i = 0; i < nvisuals; i++) {
FrameBufferProperties fbprops;
get_properties(fbprops, _visuals + i);
int quality = fbprops.get_quality(properties);
if (quality > best_quality) {
best_quality = quality;
best_result = i;
best_props = fbprops;
}
}
}
if (best_quality > 0) {
_visual = _visuals + best_result;
_context = glXCreateContext(_display, _visual, None, GL_TRUE);
if (_context) {
_fbprops = best_props;
return;
}
}
glxdisplay_cat.error()
<< "Could not find a usable pixel format.\n";
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsStateGuardian::init_temp_context
// Access: Private
// Description: Initializes the context created in choose_visual() by
// creating a temporary window and binding the context
// to that window.
////////////////////////////////////////////////////////////////////
void glxGraphicsStateGuardian::
init_temp_context() {
x11GraphicsPipe *x11_pipe;
DCAST_INTO_V(x11_pipe, get_pipe());
Window root_window = x11_pipe->get_root();
destroy_temp_xwindow();
_temp_xwindow = XCreateWindow
(_display, root_window, 0, 0, 1, 1,
0, _visual->depth, InputOutput,
_visual->visual, 0, NULL);
if (_temp_xwindow == (Window)NULL) {
glxdisplay_cat.error()
<< "Could not create temporary window for context\n";
return;
}
glXMakeCurrent(_display, _temp_xwindow, _context);
reset();
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsStateGuardian::destroy_temp_xwindow
// Access: Private
// Description: Destroys the temporary unmapped window created by
// init_temp_context().
////////////////////////////////////////////////////////////////////
void glxGraphicsStateGuardian::
destroy_temp_xwindow() {
if (_temp_xwindow != (Window)NULL) {
XDestroyWindow(_display, _temp_xwindow);
_temp_xwindow = (Window)NULL;
}
}

View File

@ -20,6 +20,9 @@
#include "glgsg.h"
#include "glxGraphicsPipe.h"
// Don't pick up the system glxext.h; use our own, which is better.
#define __glxext_h_
#include <GL/glx.h>
#if defined(GLX_VERSION_1_4)
@ -39,7 +42,7 @@ extern "C" void (*glXGetProcAddressARB(const GLubyte *procName))( void );
// This must be included after we have included glgsg.h (which
// includes gl.h).
#include "glxext.h"
#include "panda_glxext.h"
// drose: the version of GL/glx.h that ships with Fedora Core 2 seems
// to define GLX_VERSION_1_4, but for some reason does not define
@ -69,17 +72,11 @@ typedef int (* PFNGLXSWAPINTERVALSGIPROC) (int interval);
////////////////////////////////////////////////////////////////////
class glxGraphicsStateGuardian : public GLGraphicsStateGuardian {
public:
#ifdef HAVE_GLXFBCONFIG
typedef GLXFBConfig fbconfig;
#else
typedef int fbconfig;
#endif
INLINE const FrameBufferProperties &get_fb_properties() const;
void get_properties(FrameBufferProperties &properties, XVisualInfo *visual);
void get_properties_advanced(FrameBufferProperties &properties,
bool &pbuffer_supported, bool &pixmap_supported,
bool &slow, fbconfig config);
bool &context_has_pbuffer, bool &pixmap_supported,
bool &slow, GLXFBConfig config);
void choose_pixel_format(const FrameBufferProperties &properties,
Display *_display,
int _screen,
@ -100,13 +97,30 @@ public:
int _screen;
XVisualInfo *_visual;
XVisualInfo *_visuals;
fbconfig _fbconfig;
GLXFBConfig _fbconfig;
FrameBufferProperties _fbprops;
bool _context_has_pbuffer; // true if the particular fbconfig supports pbuffers
bool _context_has_pixmap;
bool _slow;
public:
bool _supports_swap_control;
PFNGLXSWAPINTERVALSGIPROC _glXSwapIntervalSGI;
bool _supports_fbconfig;
PFNGLXCHOOSEFBCONFIGPROC _glXChooseFBConfig;
PFNGLXCREATENEWCONTEXTPROC _glXCreateNewContext;
PFNGLXGETVISUALFROMFBCONFIGPROC _glXGetVisualFromFBConfig;
PFNGLXGETFBCONFIGATTRIBPROC _glXGetFBConfigAttrib;
PFNGLXCREATEPIXMAPPROC _glXCreatePixmap;
bool _supports_pbuffer; // true if the interface is available.
bool _uses_sgix_pbuffer;
PFNGLXCREATEPBUFFERPROC _glXCreatePbuffer;
PFNGLXCREATEGLXPBUFFERSGIXPROC _glXCreateGLXPbufferSGIX;
PFNGLXDESTROYPBUFFERPROC _glXDestroyPbuffer;
protected:
virtual void gl_flush() const;
virtual GLenum gl_get_error() const;
@ -119,13 +133,16 @@ private:
void *get_system_func(const char *name);
void show_glx_client_string(const string &name, int id);
void show_glx_server_string(const string &name, int id);
void choose_visual(const FrameBufferProperties &properties);
void init_temp_context();
void destroy_temp_xwindow();
int _glx_version_major, _glx_version_minor;
void *_libgl_handle;
bool _checked_get_proc_address;
PFNGLXGETPROCADDRESSPROC _glXGetProcAddress;
Window _temp_xwindow;
public:
static TypeHandle get_class_type() {

View File

@ -188,15 +188,11 @@ open_window() {
}
Visual *visual = _visual_info->visual;
#ifdef HAVE_GLXFBCONFIG
if (glxgsg->_fbconfig != None) {
setup_colormap(glxgsg->_fbconfig);
} else {
setup_colormap(_visual_info);
}
#else
setup_colormap(_visual_info);
#endif // HAVE_GLXFBCONFIG
if (!x11GraphicsWindow::open_window()) {
return false;
@ -218,7 +214,6 @@ open_window() {
return true;
}
#ifdef HAVE_GLXFBCONFIG
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsWindow::setup_colormap
// Access: Private
@ -227,7 +222,11 @@ open_window() {
////////////////////////////////////////////////////////////////////
void glxGraphicsWindow::
setup_colormap(GLXFBConfig fbconfig) {
XVisualInfo *visual_info = glXGetVisualFromFBConfig(_display, fbconfig);
glxGraphicsStateGuardian *glxgsg;
DCAST_INTO_V(glxgsg, _gsg);
nassertv(glxgsg->_supports_fbconfig);
XVisualInfo *visual_info = glxgsg->_glXGetVisualFromFBConfig(_display, fbconfig);
if (visual_info == NULL) {
// No X visual; no need to set up a colormap.
return;
@ -244,7 +243,7 @@ setup_colormap(GLXFBConfig fbconfig) {
switch (visual_class) {
case PseudoColor:
rc = glXGetFBConfigAttrib(_display, fbconfig, GLX_RGBA, &is_rgb);
rc = glxgsg->_glXGetFBConfigAttrib(_display, fbconfig, GLX_RGBA, &is_rgb);
if (rc == 0 && is_rgb) {
glxdisplay_cat.warning()
<< "mesa pseudocolor not supported.\n";
@ -274,7 +273,6 @@ setup_colormap(GLXFBConfig fbconfig) {
break;
}
}
#endif // HAVE_GLXFBCONFIG
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsWindow::setup_colormap

View File

@ -46,10 +46,7 @@ protected:
virtual bool open_window();
private:
#ifdef HAVE_GLXFBCONFIG
virtual void setup_colormap(GLXFBConfig fbconfig);
#endif // HAVE_GLXFBCONFIG
virtual void setup_colormap(XVisualInfo *visual);
public:

View File

@ -1,5 +1,5 @@
#ifndef __glxext_h_
#define __glxext_h_
#ifndef panda__glxext_h_
#define panda__glxext_h_
#ifdef __cplusplus
extern "C" {