fall back to older XVisualInfo interface if GLXFBConfig doesn't return any available options

This commit is contained in:
David Rose 2004-04-26 18:38:44 +00:00
parent fd24bb7a43
commit 3d2f33e10e
6 changed files with 427 additions and 28 deletions

View File

@ -185,25 +185,44 @@ make_gsg(const FrameBufferProperties &properties,
}
FrameBufferProperties new_properties = properties;
GLXContext context = NULL;
GLXFBConfig fbconfig = choose_fbconfig(new_properties);
if (fbconfig == None) {
return NULL;
XVisualInfo *visual = NULL;
if (fbconfig != None) {
context =
glXCreateNewContext(_display, fbconfig, GLX_RGBA_TYPE, share_context,
GL_TRUE);
}
if (context == NULL) {
// If we couldn't create a context with the fbconfig interface,
// try falling back to the older XVisual interface.
visual = choose_visual(new_properties);
if (visual != (XVisualInfo *)NULL) {
context = glXCreateContext(_display, visual, None, GL_TRUE);
fbconfig = None;
}
}
// Attempt to create a GL context.
GLXContext context =
glXCreateNewContext(_display, fbconfig, GLX_RGBA_TYPE, share_context,
GL_TRUE);
if (context == NULL) {
glxdisplay_cat.error()
<< "Could not create GL context.\n";
return NULL;
}
if (visual == (XVisualInfo *)NULL) {
// If we used the fbconfig to open the context, we still need to
// get the associated XVisual.
nassertr(fbconfig != None, NULL);
visual = glXGetVisualFromFBConfig(_display, fbconfig);
}
// Now we can make a GSG.
PT(glxGraphicsStateGuardian) gsg =
new glxGraphicsStateGuardian(new_properties, share_gsg, context, fbconfig,
_display, _screen);
new glxGraphicsStateGuardian(new_properties, share_gsg, context,
fbconfig, visual, _display, _screen);
return gsg.p();
}
@ -282,7 +301,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
// information: we don't care about that much detail.
NotifySeverity show_fbconfig_severity = NS_debug;
if (fbconfig == NULL) {
if (fbconfig == None) {
glxdisplay_cat.info()
<< "glxGraphicsWindow::choose_fbconfig() - fbconfig with requested "
<< "capabilities not found; trying for lesser fbconfig.\n";
@ -308,7 +327,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
fbconfig = try_for_fbconfig(frame_buffer_mode, 1, 1);
}
if (fbconfig == NULL) {
if (fbconfig == None) {
// Ok, not good enough. Now try to eliminate options, but keep
// as many bits as we asked for.
@ -348,7 +367,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
tried_masks.insert(frame_buffer_mode);
int i;
for (i = 0; fbconfig == NULL && strip_properties[i] != 0; i++) {
for (i = 0; fbconfig == None && strip_properties[i] != 0; i++) {
int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
if (tried_masks.insert(new_frame_buffer_mode).second) {
fbconfig = try_for_fbconfig(new_frame_buffer_mode, want_depth_bits,
@ -360,10 +379,10 @@ choose_fbconfig(FrameBufferProperties &properties) const {
tried_masks.clear();
tried_masks.insert(frame_buffer_mode);
if (fbconfig == NULL) {
if (fbconfig == None) {
// Try once more, this time eliminating all of the size
// requests.
for (i = 0; fbconfig == NULL && strip_properties[i] != 0; i++) {
for (i = 0; fbconfig == None && strip_properties[i] != 0; i++) {
int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
if (tried_masks.insert(new_frame_buffer_mode).second) {
fbconfig = try_for_fbconfig(new_frame_buffer_mode, 1, 1);
@ -372,16 +391,16 @@ choose_fbconfig(FrameBufferProperties &properties) const {
}
}
if (fbconfig == NULL) {
if (fbconfig == None) {
// Here's our last-ditch desparation attempt: give us any GLX
// fbconfig at all!
fbconfig = try_for_fbconfig(0, 1, 1);
}
if (fbconfig == NULL) {
if (fbconfig == None) {
glxdisplay_cat.error()
<< "Could not get any GLX fbconfig.\n";
return NULL;
return None;
}
}
}
@ -389,7 +408,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
glxdisplay_cat.info()
<< "Selected suitable GLX fbconfig.\n";
// Now update our frambuffer_mode and bit depth appropriately.
// 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;
@ -457,7 +476,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
// Description: Attempt to get the requested fbconfig, if it is
// available. It's just a wrapper around
// glXChooseFBConfig(). It returns the fbconfig
// information if possible, or NULL if it is not.
// information if possible, or None if it is not.
////////////////////////////////////////////////////////////////////
GLXFBConfig glxGraphicsPipe::
try_for_fbconfig(int framebuffer_mode,
@ -538,17 +557,17 @@ try_for_fbconfig(int framebuffer_mode,
attrib_list[n++] = want_color_component_bits;
}
}
#if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
/*
if (framebuffer_mode & FrameBufferProperties::FM_multisample) {
glxdisplay_cat.debug(false) << " MULTISAMPLE";
attrib_list[n++] = GLX_SAMPLES_SGIS;
// We decide 4 is minimum number of samples
attrib_list[n++] = 4;
}
#endif
*/
// Terminate the list
nassertr(n < max_attrib_list, NULL);
nassertr(n < max_attrib_list, None);
attrib_list[n] = (int)None;
int num_configs = 0;
@ -576,6 +595,326 @@ try_for_fbconfig(int framebuffer_mode,
return fbconfig;
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPipe::choose visual
// Access: Private
// Description: Selects an appropriate X visual for the given frame
// buffer properties. Returns the visual pointer if
// successful, or NULL otherwise.
//
// If successful, this may modify properties to reflect
// the actual visual chosen.
//
// This is an older GLX interface, replaced by the new
// fbconfig interface. However, some implementations of
// GLX may not support fbconfig, so we have to have this
// code as a fallback.
////////////////////////////////////////////////////////////////////
XVisualInfo *glxGraphicsPipe::
choose_visual(FrameBufferProperties &properties) const {
int frame_buffer_mode = 0;
int want_depth_bits = 0;
int want_color_bits = 0;
if (properties.has_frame_buffer_mode()) {
frame_buffer_mode = properties.get_frame_buffer_mode();
}
if (properties.has_depth_bits()) {
want_depth_bits = properties.get_depth_bits();
}
if (properties.has_color_bits()) {
want_color_bits = properties.get_color_bits();
}
/*
if (frame_buffer_mode & FrameBufferProperties::FM_multisample) {
if (!glx_supports("GLX_SGIS_multisample")) {
glxdisplay_cat.info()
<< "multisample not supported by this glx implementation.\n";
frame_buffer_mode &= ~FrameBufferProperties::FM_multisample;
}
}
*/
XVisualInfo *visual =
try_for_visual(frame_buffer_mode, want_depth_bits, want_color_bits);
// This is the severity level at which we'll report the details of
// the visual we actually do find. Normally, it's debug-level
// information: we don't care about that much detail.
NotifySeverity show_visual_severity = NS_debug;
if (visual == NULL) {
glxdisplay_cat.info()
<< "glxGraphicsWindow::choose_visual() - visual with requested\n"
<< " capabilities not found; trying for lesser visual.\n";
// If we're unable to get the visual we asked for, however, we
// probably *do* care to know the details about what we actually
// got, even if we don't have debug mode set. So we'll report the
// visual at a higher level.
show_visual_severity = NS_info;
bool special_size_request =
(want_depth_bits != 1 || want_color_bits != 1);
// We try to be smart about choosing a close match for the visual.
// First, we'll eliminate some of the more esoteric options one at
// a time, then two at a time, and finally we'll try just the bare
// minimum.
if (special_size_request) {
// Actually, first we'll eliminate all of the minimum sizes, to
// try to open a window with all of the requested options, but
// maybe not as many bits in some options as we'd like.
visual = try_for_visual(frame_buffer_mode, 1, 1);
}
if (visual == NULL) {
// Ok, not good enough. Now try to eliminate options, but keep
// as many bits as we asked for.
// This array keeps the bitmasks of options that we pull out of
// the requested frame_buffer_mode, in order.
static const int strip_properties[] = {
// One esoteric option removed.
FrameBufferProperties::FM_multisample,
FrameBufferProperties::FM_stencil,
FrameBufferProperties::FM_accum,
FrameBufferProperties::FM_alpha,
FrameBufferProperties::FM_stereo,
// Two esoteric options removed.
FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_multisample,
FrameBufferProperties::FM_accum | FrameBufferProperties::FM_multisample,
FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_multisample,
FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum,
FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo,
FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_multisample,
FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
// All esoteric options removed.
FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
// All esoteric options, plus some we'd really really prefer,
// removed.
FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample | FrameBufferProperties::FM_double_buffer,
// A zero marks the end of the array.
0
};
pset<int> tried_masks;
tried_masks.insert(frame_buffer_mode);
int i;
for (i = 0; visual == NULL && strip_properties[i] != 0; i++) {
int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
if (tried_masks.insert(new_frame_buffer_mode).second) {
visual = try_for_visual(new_frame_buffer_mode, want_depth_bits,
want_color_bits);
}
}
if (special_size_request) {
tried_masks.clear();
tried_masks.insert(frame_buffer_mode);
if (visual == NULL) {
// Try once more, this time eliminating all of the size
// requests.
for (i = 0; visual == NULL && strip_properties[i] != 0; i++) {
int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
if (tried_masks.insert(new_frame_buffer_mode).second) {
visual = try_for_visual(new_frame_buffer_mode, 1, 1);
}
}
}
}
if (visual == NULL) {
// Here's our last-ditch desparation attempt: give us any GLX
// visual at all!
visual = try_for_visual(0, 1, 1);
}
if (visual == NULL) {
glxdisplay_cat.error()
<< "Could not get any GLX visual.\n";
return NULL;
}
}
}
glxdisplay_cat.info()
<< "Got visual 0x" << hex << (int)visual->visualid << dec << ".\n";
// 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;
glXGetConfig(_display, visual, GLX_RGBA, &render_mode);
glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &double_buffer);
glXGetConfig(_display, visual, GLX_STEREO, &stereo);
glXGetConfig(_display, visual, GLX_RED_SIZE, &red_size);
glXGetConfig(_display, visual, GLX_GREEN_SIZE, &green_size);
glXGetConfig(_display, visual, GLX_BLUE_SIZE, &blue_size);
glXGetConfig(_display, visual, GLX_ALPHA_SIZE, &alpha_size);
glXGetConfig(_display, visual, GLX_ACCUM_RED_SIZE, &ared_size);
glXGetConfig(_display, visual, GLX_ACCUM_GREEN_SIZE, &agreen_size);
glXGetConfig(_display, visual, GLX_ACCUM_BLUE_SIZE, &ablue_size);
glXGetConfig(_display, visual, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
glXGetConfig(_display, visual, GLX_DEPTH_SIZE, &depth_size);
glXGetConfig(_display, visual, GLX_STENCIL_SIZE, &stencil_size);
frame_buffer_mode = 0;
if (double_buffer) {
frame_buffer_mode |= FrameBufferProperties::FM_double_buffer;
}
if (stereo) {
frame_buffer_mode |= FrameBufferProperties::FM_stereo;
}
if (!render_mode) {
frame_buffer_mode |= FrameBufferProperties::FM_index;
}
if (stencil_size != 0) {
frame_buffer_mode |= FrameBufferProperties::FM_stencil;
}
if (depth_size != 0) {
frame_buffer_mode |= FrameBufferProperties::FM_depth;
}
if (alpha_size != 0) {
frame_buffer_mode |= FrameBufferProperties::FM_alpha;
}
if (ared_size + agreen_size + ablue_size != 0) {
frame_buffer_mode |= FrameBufferProperties::FM_accum;
}
properties.set_frame_buffer_mode(frame_buffer_mode);
properties.set_color_bits(red_size + green_size + blue_size + alpha_size);
properties.set_depth_bits(depth_size);
if (glxdisplay_cat.is_on(show_visual_severity)) {
glxdisplay_cat.out(show_visual_severity)
<< "GLX Visual Info (# bits of each):" << endl
<< " RGBA: " << red_size << " " << green_size << " " << blue_size
<< " " << alpha_size << endl
<< " Accum RGBA: " << ared_size << " " << agreen_size << " "
<< ablue_size << " " << aalpha_size << endl
<< " Depth: " << depth_size << endl
<< " Stencil: " << stencil_size << endl
<< " DoubleBuffer? " << double_buffer << endl
<< " Stereo? " << stereo << endl;
}
return visual;
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPipe::try_for_visual
// Access: Private
// Description: Attempt to get the requested visual, if it is
// available. It's just a wrapper around
// glXChooseVisual(). It returns the visual information
// if possible, or NULL if it is not.
//
// This is an older GLX interface, replaced by the new
// fbconfig interface. However, some implementations of
// GLX may not support fbconfig, so we have to have this
// code as a fallback.
////////////////////////////////////////////////////////////////////
XVisualInfo *glxGraphicsPipe::
try_for_visual(int framebuffer_mode,
int want_depth_bits, int want_color_bits) const {
static const int max_attrib_list = 32;
int attrib_list[max_attrib_list];
int n=0;
glxdisplay_cat.debug()
<< "Trying for visual with: RGB(" << want_color_bits << ")";
int want_color_component_bits;
if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
want_color_component_bits = max(want_color_bits / 4, 1);
} else {
want_color_component_bits = max(want_color_bits / 3, 1);
}
attrib_list[n++] = GLX_RGBA;
attrib_list[n++] = GLX_RED_SIZE;
attrib_list[n++] = want_color_component_bits;
attrib_list[n++] = GLX_GREEN_SIZE;
attrib_list[n++] = want_color_component_bits;
attrib_list[n++] = GLX_BLUE_SIZE;
attrib_list[n++] = want_color_component_bits;
if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
glxdisplay_cat.debug(false) << " ALPHA";
attrib_list[n++] = GLX_ALPHA_SIZE;
attrib_list[n++] = want_color_component_bits;
}
if (framebuffer_mode & FrameBufferProperties::FM_double_buffer) {
glxdisplay_cat.debug(false) << " DOUBLEBUFFER";
attrib_list[n++] = GLX_DOUBLEBUFFER;
}
if (framebuffer_mode & FrameBufferProperties::FM_stereo) {
glxdisplay_cat.debug(false) << " STEREO";
attrib_list[n++] = GLX_STEREO;
}
if (framebuffer_mode & FrameBufferProperties::FM_depth) {
glxdisplay_cat.debug(false) << " DEPTH(" << want_depth_bits << ")";
attrib_list[n++] = GLX_DEPTH_SIZE;
attrib_list[n++] = want_depth_bits;
}
if (framebuffer_mode & FrameBufferProperties::FM_stencil) {
glxdisplay_cat.debug(false) << " STENCIL";
attrib_list[n++] = GLX_STENCIL_SIZE;
attrib_list[n++] = 1;
}
if (framebuffer_mode & FrameBufferProperties::FM_accum) {
glxdisplay_cat.debug(false) << " ACCUM";
attrib_list[n++] = GLX_ACCUM_RED_SIZE;
attrib_list[n++] = want_color_component_bits;
attrib_list[n++] = GLX_ACCUM_GREEN_SIZE;
attrib_list[n++] = want_color_component_bits;
attrib_list[n++] = GLX_ACCUM_BLUE_SIZE;
attrib_list[n++] = want_color_component_bits;
if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
attrib_list[n++] = GLX_ACCUM_ALPHA_SIZE;
attrib_list[n++] = want_color_component_bits;
}
}
/*
if (framebuffer_mode & FrameBufferProperties::FM_multisample) {
glxdisplay_cat.debug(false) << " MULTISAMPLE";
attrib_list[n++] = GLX_SAMPLES_SGIS;
// We decide 4 is minimum number of samples
attrib_list[n++] = 4;
}
*/
// Terminate the list
nassertr(n < max_attrib_list, NULL);
attrib_list[n] = (int)None;
XVisualInfo *vinfo = glXChooseVisual(_display, _screen, attrib_list);
if (glxdisplay_cat.is_debug()) {
if (vinfo != NULL) {
glxdisplay_cat.debug(false) << ", match found!\n";
} else {
glxdisplay_cat.debug(false) << ", no match.\n";
}
}
return vinfo;
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPipe::make_hidden_cursor
// Access: Private

View File

@ -93,6 +93,11 @@ private:
GLXFBConfig choose_fbconfig(FrameBufferProperties &properties) const;
GLXFBConfig try_for_fbconfig(int framebuffer_mode,
int want_depth_bits, int want_color_bits) const;
XVisualInfo *choose_visual(FrameBufferProperties &properties) const;
XVisualInfo *try_for_visual(int framebuffer_mode,
int want_depth_bits, int want_color_bits) const;
void make_hidden_cursor();
void release_hidden_cursor();

View File

@ -30,10 +30,11 @@ glxGraphicsStateGuardian::
glxGraphicsStateGuardian(const FrameBufferProperties &properties,
glxGraphicsStateGuardian *share_with,
GLXContext context, GLXFBConfig fbconfig,
Display *display, int screen) :
XVisualInfo *visual, Display *display, int screen) :
GLGraphicsStateGuardian(properties),
_context(context),
_fbconfig(fbconfig),
_visual(visual),
_display(display),
_screen(screen)
{
@ -49,6 +50,9 @@ glxGraphicsStateGuardian(const FrameBufferProperties &properties,
////////////////////////////////////////////////////////////////////
glxGraphicsStateGuardian::
~glxGraphicsStateGuardian() {
if (_visual != (XVisualInfo *)NULL) {
XFree(_visual);
}
if (_context != (GLXContext)NULL) {
glXDestroyContext(_display, _context);
_context = (GLXContext)NULL;

View File

@ -34,11 +34,12 @@ public:
glxGraphicsStateGuardian(const FrameBufferProperties &properties,
glxGraphicsStateGuardian *share_with,
GLXContext context, GLXFBConfig fbconfig,
Display *display, int screen);
XVisualInfo *visual, Display *display, int screen);
virtual ~glxGraphicsStateGuardian();
GLXContext _context;
GLXFBConfig _fbconfig;
XVisualInfo *_visual;
Display *_display;
int _screen;

View File

@ -505,9 +505,7 @@ open_window() {
glxGraphicsStateGuardian *glxgsg;
DCAST_INTO_R(glxgsg, _gsg, false);
XVisualInfo *visual_info =
glXGetVisualFromFBConfig(_display, glxgsg->_fbconfig);
XVisualInfo *visual_info = glxgsg->_visual;
if (visual_info == NULL) {
// No X visual for this fbconfig; how can we open the window?
glxdisplay_cat.error()
@ -516,7 +514,6 @@ open_window() {
}
Visual *visual = visual_info->visual;
int depth = visual_info->depth;
XFree(visual_info);
if (!_properties.has_origin()) {
@ -528,7 +525,11 @@ open_window() {
Window root_window = glx_pipe->get_root();
setup_colormap(glxgsg->_fbconfig);
if (glxgsg->_fbconfig != None) {
setup_colormap(glxgsg->_fbconfig);
} else {
setup_colormap(visual_info);
}
_event_mask =
ButtonPressMask | ButtonReleaseMask |
@ -736,6 +737,54 @@ setup_colormap(GLXFBConfig fbconfig) {
}
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsWindow::setup_colormap
// Access: Private
// Description: Allocates a colormap appropriate to the visual and
// stores in in the _colormap method.
////////////////////////////////////////////////////////////////////
void glxGraphicsWindow::
setup_colormap(XVisualInfo *visual) {
glxGraphicsPipe *glx_pipe;
DCAST_INTO_V(glx_pipe, _pipe);
Window root_window = glx_pipe->get_root();
int visual_class = visual->c_class;
int rc, is_rgb;
switch (visual_class) {
case PseudoColor:
rc = glXGetConfig(_display, visual, GLX_RGBA, &is_rgb);
if (rc == 0 && is_rgb) {
glxdisplay_cat.warning()
<< "mesa pseudocolor not supported.\n";
// this is a terrible terrible hack, but it seems to work
_colormap = (Colormap)0;
} else {
_colormap = XCreateColormap(_display, root_window,
visual->visual, AllocAll);
}
break;
case TrueColor:
case DirectColor:
_colormap = XCreateColormap(_display, root_window,
visual->visual, AllocNone);
break;
case StaticColor:
case StaticGray:
case GrayScale:
_colormap = XCreateColormap(_display, root_window,
visual->visual, AllocNone);
break;
default:
glxdisplay_cat.error()
<< "Could not allocate a colormap for visual class "
<< visual_class << ".\n";
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsWindow::handle_keystroke
// Access: Private

View File

@ -56,6 +56,7 @@ private:
void set_wm_properties(const WindowProperties &properties);
void setup_colormap(GLXFBConfig fbconfig);
void setup_colormap(XVisualInfo *visual);
void handle_keystroke(XKeyEvent &event);
void handle_keypress(XKeyEvent &event);
void handle_keyrelease(XKeyEvent &event);