glxGraphicsPixmap

This commit is contained in:
David Rose 2009-03-12 15:43:18 +00:00
parent ea1f1d632d
commit 6e64da12a6
12 changed files with 441 additions and 38 deletions

View File

@ -16,6 +16,7 @@
config_glxdisplay.cxx config_glxdisplay.h \
glxGraphicsBuffer.h glxGraphicsBuffer.I glxGraphicsBuffer.cxx \
glxGraphicsPipe.I glxGraphicsPipe.cxx glxGraphicsPipe.h \
glxGraphicsPixmap.h glxGraphicsPixmap.I glxGraphicsPixmap.cxx \
glxGraphicsWindow.h glxGraphicsWindow.I glxGraphicsWindow.cxx \
glxGraphicsStateGuardian.h glxGraphicsStateGuardian.I \
glxGraphicsStateGuardian.cxx \

View File

@ -15,6 +15,7 @@
#include "config_glxdisplay.h"
#include "glxGraphicsBuffer.h"
#include "glxGraphicsPipe.h"
#include "glxGraphicsPixmap.h"
#include "glxGraphicsWindow.h"
#include "glxGraphicsStateGuardian.h"
#include "graphicsPipeSelection.h"
@ -97,6 +98,7 @@ init_libglxdisplay() {
glxGraphicsBuffer::init_type();
#endif // HAVE_GLXFBCONFIG
glxGraphicsPipe::init_type();
glxGraphicsPixmap::init_type();
glxGraphicsWindow::init_type();
glxGraphicsStateGuardian::init_type();

View File

@ -161,7 +161,6 @@ close_buffer() {
////////////////////////////////////////////////////////////////////
bool glxGraphicsBuffer::
open_buffer() {
glxGraphicsPipe *glx_pipe;
DCAST_INTO_R(glx_pipe, _pipe, false);
@ -170,7 +169,7 @@ open_buffer() {
if (_gsg == 0) {
// There is no old gsg. Create a new one.
glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true, false);
_gsg = glxgsg;
} else {
// If the old gsg has the wrong pixel format, create a
@ -178,7 +177,7 @@ open_buffer() {
DCAST_INTO_R(glxgsg, _gsg, false);
if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) {
glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true, false);
_gsg = glxgsg;
}
}

View File

@ -15,6 +15,7 @@
#include "glxGraphicsPipe.h"
#include "glxGraphicsWindow.h"
#include "glxGraphicsBuffer.h"
#include "glxGraphicsPixmap.h"
#include "glxGraphicsStateGuardian.h"
#include "config_glxdisplay.h"
#include "frameBufferProperties.h"
@ -272,24 +273,49 @@ make_output(const string &name,
return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
#ifdef HAVE_GLXFBCONFIG
// Third thing to try: a glxGraphicsBuffer
if (retry == 2) {
if ((!support_rtt)||
((flags&BF_require_parasite)!=0)||
if (((flags&BF_require_parasite)!=0)||
((flags&BF_require_window)!=0)||
((flags&BF_resizeable)!=0)||
((flags&BF_size_track_host)!=0)||
((flags&BF_rtt_cumulative)!=0)||
((flags&BF_can_bind_every)!=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);
}
#endif // HAVE_GLXFBCONFIG
// Third thing to try: a glxGraphicsPixmap.
if (retry == 3) {
if (((flags&BF_require_parasite)!=0)||
((flags&BF_require_window)!=0)||
((flags&BF_resizeable)!=0)||
((flags&BF_size_track_host)!=0)) {
return NULL;
}
if (((flags&BF_rtt_cumulative)!=0)||
((flags&BF_can_bind_every)!=0)) {
return NULL;
}
return new glxGraphicsPixmap(engine, this, name, fb_prop, win_prop,
flags, gsg, host);
}
// Nothing else left to try.
return NULL;

View File

@ -0,0 +1,14 @@
// Filename: glxGraphicsPixmap.I
// Created by: drose (10Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,262 @@
// Filename: glxGraphicsPixmap.cxx
// Created by: drose (10Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "glxGraphicsPixmap.h"
#include "glxGraphicsWindow.h"
#include "glxGraphicsStateGuardian.h"
#include "config_glxdisplay.h"
#include "glxGraphicsPipe.h"
#include "graphicsPipe.h"
#include "glgsg.h"
#include "pStatTimer.h"
TypeHandle glxGraphicsPixmap::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPixmap::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
glxGraphicsPixmap::
glxGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe,
const string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg,
GraphicsOutput *host) :
GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
{
glxGraphicsPipe *glx_pipe;
DCAST_INTO_V(glx_pipe, _pipe);
_display = glx_pipe->get_display();
_drawable = None;
_x_pixmap = None;
_glx_pixmap = None;
// Since the pixmap never gets flipped, we get screenshots from the
// same pixmap we draw into.
_screenshot_buffer_type = _draw_buffer_type;
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPixmap::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
glxGraphicsPixmap::
~glxGraphicsPixmap() {
nassertv(_x_pixmap == None && _glx_pixmap == None);
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPixmap::begin_frame
// Access: Public, Virtual
// Description: This function will be called within the draw thread
// before beginning rendering for a given frame. It
// should do whatever setup is required, and return true
// if the frame should be rendered, or false if it
// should be skipped.
////////////////////////////////////////////////////////////////////
bool glxGraphicsPixmap::
begin_frame(FrameMode mode, Thread *current_thread) {
PStatTimer timer(_make_current_pcollector, current_thread);
begin_frame_spam(mode);
if (_gsg == (GraphicsStateGuardian *)NULL) {
return false;
}
glxGraphicsStateGuardian *glxgsg;
DCAST_INTO_R(glxgsg, _gsg, false);
glXMakeCurrent(_display, _glx_pixmap, glxgsg->_context);
// Now that we have made the context current to a window, we can
// reset the GSG state if this is the first time it has been used.
// (We can't just call reset() when we construct the GSG, because
// reset() requires having a current context.)
glxgsg->reset_if_new();
if (mode == FM_render) {
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
_textures[i]._rtm_mode = RTM_copy_texture;
}
}
clear_cube_map_selection();
}
_gsg->set_current_properties(&get_fb_properties());
return _gsg->begin_frame(current_thread);
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPixmap::end_frame
// Access: Public, Virtual
// Description: This function will be called within the draw thread
// after rendering is completed for a given frame. It
// should do whatever finalization is required.
////////////////////////////////////////////////////////////////////
void glxGraphicsPixmap::
end_frame(FrameMode mode, Thread *current_thread) {
end_frame_spam(mode);
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
if (mode == FM_render) {
copy_to_textures();
}
_gsg->end_frame(current_thread);
if (mode == FM_render) {
trigger_flip();
if (_one_shot) {
prepare_for_deletion();
}
clear_cube_map_selection();
}
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPixmap::close_buffer
// Access: Protected, Virtual
// Description: Closes the pixmap right now. Called from the window
// thread.
////////////////////////////////////////////////////////////////////
void glxGraphicsPixmap::
close_buffer() {
if (_gsg != (GraphicsStateGuardian *)NULL) {
glXMakeCurrent(_display, None, NULL);
_gsg.clear();
_active = false;
}
if (_glx_pixmap != None) {
glXDestroyGLXPixmap(_display, _glx_pixmap);
_glx_pixmap = None;
}
if (_x_pixmap != None) {
XFreePixmap(_display, _x_pixmap);
_x_pixmap = None;
}
_is_valid = false;
}
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsPixmap::open_buffer
// Access: Protected, Virtual
// Description: Opens the pixmap right now. Called from the window
// thread. Returns true if the pixmap is successfully
// opened, or false if there was a problem.
////////////////////////////////////////////////////////////////////
bool glxGraphicsPixmap::
open_buffer() {
cerr << "open_buffer\n";
glxGraphicsPipe *glx_pipe;
DCAST_INTO_R(glx_pipe, _pipe, false);
// GSG Creation/Initialization
glxGraphicsStateGuardian *glxgsg;
if (_gsg == 0) {
// There is no old gsg. Create a new one.
glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL);
glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
_gsg = glxgsg;
} else {
// 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)) {
glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
_gsg = glxgsg;
}
}
XVisualInfo *visual_info = glxgsg->_visual;
if (visual_info == NULL) {
// No X visual for this fbconfig; how can we create the pixmap?
glxdisplay_cat.error()
<< "No X visual: cannot create pixmap.\n";
return false;
}
_drawable = glx_pipe->get_root();
if (_host != NULL) {
cerr << "got host: " << _host->get_type() << "\n";
if (_host->is_of_type(glxGraphicsWindow::get_class_type())) {
glxGraphicsWindow *win = DCAST(glxGraphicsWindow, _host);
_drawable = win->get_xwindow();
} else if (_host->is_of_type(glxGraphicsPixmap::get_class_type())) {
glxGraphicsPixmap *pix = DCAST(glxGraphicsPixmap, _host);
_drawable = pix->_drawable;
}
}
cerr << "creating pixmap, root = " << _drawable
<< ", size = " << _x_size << " " << _y_size << ", depth = "
<< visual_info->depth << "\n";
_x_pixmap = XCreatePixmap(_display, _drawable,
_x_size, _y_size, visual_info->depth);
cerr << "got " << _x_pixmap << "\n";
if (_x_pixmap == None) {
glxdisplay_cat.error()
<< "Failed to create X pixmap.\n";
close_buffer();
return false;
}
cerr << "creating glx pixmap\n";
#ifdef HAVE_GLXFBCONFIG
if (glxgsg->_fbconfig) {
// Use the FBConfig to create the pixmap.
cerr << "fbconfig\n";
_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);
}
cerr << "got " << _glx_pixmap << "\n";
if (_glx_pixmap == None) {
glxdisplay_cat.error()
<< "Failed to create GLX pixmap.\n";
close_buffer();
return false;
}
cerr << "making current, context = " << glxgsg->_context << "\n";
glXMakeCurrent(_display, _glx_pixmap, glxgsg->_context);
cerr << "context = " << glxgsg->_context << "\n";
glxgsg->reset_if_new();
if (!glxgsg->is_valid()) {
close_buffer();
return false;
}
if (!glxgsg->get_fb_properties().verify_hardware_software
(_fb_properties, glxgsg->get_gl_renderer())) {
close_buffer();
return false;
}
_fb_properties = glxgsg->get_fb_properties();
_is_valid = true;
return true;
}

View File

@ -0,0 +1,75 @@
// Filename: glxGraphicsPixmap.h
// Created by: drose (10Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef GLXGRAPHICSPIXMAP_H
#define GLXGRAPHICSPIXMAP_H
#include "pandabase.h"
#include "glxGraphicsPipe.h"
#include "graphicsBuffer.h"
////////////////////////////////////////////////////////////////////
// Class : glxGraphicsPixmap
// Description : Another offscreen buffer in the GLX environment. This
// creates a Pixmap object, which is probably less
// efficient than a GLXPBuffer, so this class is a
// second choice to glxGraphicsBuffer. However, this
// might be the only option for some graphics drivers.
////////////////////////////////////////////////////////////////////
class glxGraphicsPixmap : public GraphicsBuffer {
public:
glxGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe,
const string &name,
const FrameBufferProperties &fb_prop,
const WindowProperties &win_prop,
int flags,
GraphicsStateGuardian *gsg,
GraphicsOutput *host);
virtual ~glxGraphicsPixmap();
virtual bool begin_frame(FrameMode mode, Thread *current_thread);
virtual void end_frame(FrameMode mode, Thread *current_thread);
protected:
virtual void close_buffer();
virtual bool open_buffer();
private:
Display *_display;
Window _drawable;
Pixmap _x_pixmap;
GLXPixmap _glx_pixmap;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
GraphicsBuffer::init_type();
register_type(_type_handle, "glxGraphicsPixmap",
GraphicsBuffer::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "glxGraphicsPixmap.I"
#endif

View File

@ -137,8 +137,8 @@ get_properties(FrameBufferProperties &properties, XVisualInfo *visual) {
////////////////////////////////////////////////////////////////////
void glxGraphicsStateGuardian::
get_properties_advanced(FrameBufferProperties &properties,
bool &pbuffer_supported, bool &slow,
fbconfig config) {
bool &pbuffer_supported, bool &pixmap_supported,
bool &slow, fbconfig config) {
properties.clear();
@ -165,22 +165,26 @@ get_properties_advanced(FrameBufferProperties &properties,
glXGetFBConfigAttrib(_display, config, GLX_DRAWABLE_TYPE, &drawable_type);
glXGetFBConfigAttrib(_display, config, GLX_CONFIG_CAVEAT, &caveat);
if ((drawable_type & GLX_WINDOW_BIT)==0) {
// If we return a set of properties without setting either
// rgb_color or indexed_color, then this indicates a visual
// that's no good for any kind of rendering.
return;
}
pbuffer_supported = false;
if ((drawable_type & GLX_PBUFFER_BIT)!=0) {
pbuffer_supported = true;
}
pixmap_supported = false;
if ((drawable_type & GLX_PIXMAP_BIT)!=0) {
pixmap_supported = true;
}
if (caveat & GLX_SLOW_CONFIG) {
slow = true;
} else {
slow = false;
}
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);
@ -216,8 +220,7 @@ get_properties_advanced(FrameBufferProperties &properties,
void glxGraphicsStateGuardian::
choose_pixel_format(const FrameBufferProperties &properties,
Display *display,
int screen,
bool need_pbuffer) {
int screen, bool need_pbuffer, bool need_pixmap) {
_display = display;
_screen = screen;
@ -248,27 +251,34 @@ choose_pixel_format(const FrameBufferProperties &properties,
int best_quality = 0;
int best_result = 0;
FrameBufferProperties best_props;
if (configs != 0) {
for (int i=0; i<num_configs; i++) {
for (int i = 0; i < num_configs; ++i) {
FrameBufferProperties fbprops;
bool pbuffer_supported = false, slow = false;
get_properties_advanced(fbprops, pbuffer_supported, slow, configs[i]);
bool pbuffer_supported, pixmap_supported, slow;
get_properties_advanced(fbprops, pbuffer_supported, pixmap_supported,
slow, configs[i]);
if (glxdisplay_cat.is_debug()) {
const char *pbuffertext = pbuffer_supported ? " (pbuffer)" : "";
const char *pixmaptext = pixmap_supported ? " (pixmap)" : "";
const char *slowtext = slow ? " (slow)" : "";
glxdisplay_cat.debug()
<< i << ": " << fbprops << pbuffertext << slowtext << "\n";
<< i << ": " << fbprops << pbuffertext << pixmaptext << slowtext << "\n";
}
int quality = fbprops.get_quality(properties);
if ((quality > 0)&&(slow)) quality -= 10000000;
if ((need_pbuffer==0)||(pbuffer_supported)) {
if (quality > best_quality) {
best_quality = quality;
best_result = i;
best_props = fbprops;
}
if (need_pbuffer && !pbuffer_supported) {
continue;
}
if (need_pixmap && !pixmap_supported) {
continue;
}
if (quality > best_quality) {
best_quality = quality;
best_result = i;
best_props = fbprops;
}
}
}
@ -283,10 +293,13 @@ choose_pixel_format(const FrameBufferProperties &properties,
_visual = _visuals;
if (_visual) {
_fbprops = best_props;
cerr << "selected " << _fbconfig << "\n";
return;
}
}
// This really shouldn't happen, so I'm not too careful about cleanup.
glxdisplay_cat.error()
<< "Could not create FBConfig context!\n";
_fbconfig = 0;
_context = 0;
_visual = 0;

View File

@ -78,12 +78,12 @@ public:
INLINE const FrameBufferProperties &get_fb_properties() const;
void get_properties(FrameBufferProperties &properties, XVisualInfo *visual);
void get_properties_advanced(FrameBufferProperties &properties,
bool &supports_pbuffer, bool &slow,
fbconfig config);
bool &pbuffer_supported, bool &pixmap_supported,
bool &slow, fbconfig config);
void choose_pixel_format(const FrameBufferProperties &properties,
Display *_display,
int _screen,
bool need_pbuffer);
bool need_pbuffer, bool need_pixmap);
glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
glxGraphicsStateGuardian *share_with);

View File

@ -12,3 +12,13 @@
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: glxGraphicsWindow::get_xwindow
// Access: Public
// Description: Returns the X11 Window handle.
////////////////////////////////////////////////////////////////////
INLINE Window glxGraphicsWindow::
get_xwindow() const {
return _xwindow;
}

View File

@ -620,7 +620,7 @@ open_window() {
if (_gsg == 0) {
// There is no old gsg. Create a new one.
glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false);
_gsg = glxgsg;
} else {
// If the old gsg has the wrong pixel format, create a
@ -628,17 +628,16 @@ open_window() {
DCAST_INTO_R(glxgsg, _gsg, false);
if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) {
glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false);
glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false);
_gsg = glxgsg;
}
}
XVisualInfo *visual_info = glxgsg->_visual;
if (visual_info == NULL) {
// No X visual for this fbconfig; how can we open the window?
glxdisplay_cat.error()
<< "Cannot open window.\n";
<< "No X visual: cannot open window.\n";
return false;
}
Visual *visual = visual_info->visual;

View File

@ -45,6 +45,8 @@ public:
virtual void process_events();
virtual void set_properties_now(WindowProperties &properties);
INLINE Window get_xwindow() const;
protected:
virtual void close_window();
virtual bool open_window();