Panda3D

glxGraphicsPixmap.cxx

00001 // Filename: glxGraphicsPixmap.cxx
00002 // Created by:  drose (10Mar09)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "glxGraphicsPixmap.h"
00016 #include "glxGraphicsWindow.h"
00017 #include "glxGraphicsStateGuardian.h"
00018 #include "config_glxdisplay.h"
00019 #include "glxGraphicsPipe.h"
00020 
00021 #include "graphicsPipe.h"
00022 #include "glgsg.h"
00023 #include "pStatTimer.h"
00024 
00025 TypeHandle glxGraphicsPixmap::_type_handle;
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: glxGraphicsPixmap::Constructor
00029 //       Access: Public
00030 //  Description:
00031 ////////////////////////////////////////////////////////////////////
00032 glxGraphicsPixmap::
00033 glxGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe, 
00034                   const string &name,
00035                   const FrameBufferProperties &fb_prop,
00036                   const WindowProperties &win_prop,
00037                   int flags,
00038                   GraphicsStateGuardian *gsg,
00039                   GraphicsOutput *host) :
00040   GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00041 {
00042   glxGraphicsPipe *glx_pipe;
00043   DCAST_INTO_V(glx_pipe, _pipe);
00044   _display = glx_pipe->get_display();
00045   _drawable = None;
00046   _x_pixmap = None;
00047   _glx_pixmap = None;
00048 
00049   // Since the pixmap never gets flipped, we get screenshots from the
00050   // same pixmap we draw into.
00051   _screenshot_buffer_type = _draw_buffer_type;
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: glxGraphicsPixmap::Destructor
00056 //       Access: Public, Virtual
00057 //  Description:
00058 ////////////////////////////////////////////////////////////////////
00059 glxGraphicsPixmap::
00060 ~glxGraphicsPixmap() {
00061   nassertv(_x_pixmap == None && _glx_pixmap == None);
00062 }
00063 
00064 ////////////////////////////////////////////////////////////////////
00065 //     Function: glxGraphicsPixmap::begin_frame
00066 //       Access: Public, Virtual
00067 //  Description: This function will be called within the draw thread
00068 //               before beginning rendering for a given frame.  It
00069 //               should do whatever setup is required, and return true
00070 //               if the frame should be rendered, or false if it
00071 //               should be skipped.
00072 ////////////////////////////////////////////////////////////////////
00073 bool glxGraphicsPixmap::
00074 begin_frame(FrameMode mode, Thread *current_thread) {
00075   PStatTimer timer(_make_current_pcollector, current_thread);
00076 
00077   begin_frame_spam(mode);
00078   if (_gsg == (GraphicsStateGuardian *)NULL ||
00079       _glx_pixmap == None) {
00080     return false;
00081   }
00082 
00083   glxGraphicsStateGuardian *glxgsg;
00084   DCAST_INTO_R(glxgsg, _gsg, false);
00085   glXMakeCurrent(_display, _glx_pixmap, glxgsg->_context);
00086 
00087   // Now that we have made the context current to a window, we can
00088   // reset the GSG state if this is the first time it has been used.
00089   // (We can't just call reset() when we construct the GSG, because
00090   // reset() requires having a current context.)
00091   glxgsg->reset_if_new();
00092 
00093   if (mode == FM_render) {
00094     CDLockedReader cdata(_cycler);
00095     for (size_t i = 0; i != cdata->_textures.size(); ++i) {
00096       const RenderTexture &rt = cdata->_textures[i];
00097       RenderTextureMode rtm_mode = rt._rtm_mode;
00098       if (rtm_mode == RTM_bind_or_copy) {
00099         CDWriter cdataw(_cycler, cdata, false);
00100         nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
00101         cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
00102       }
00103     }
00104     clear_cube_map_selection();
00105   }
00106   
00107   _gsg->set_current_properties(&get_fb_properties());
00108   return _gsg->begin_frame(current_thread);
00109 }
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: glxGraphicsPixmap::end_frame
00113 //       Access: Public, Virtual
00114 //  Description: This function will be called within the draw thread
00115 //               after rendering is completed for a given frame.  It
00116 //               should do whatever finalization is required.
00117 ////////////////////////////////////////////////////////////////////
00118 void glxGraphicsPixmap::
00119 end_frame(FrameMode mode, Thread *current_thread) {
00120   end_frame_spam(mode);
00121   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00122 
00123   if (mode == FM_render) {
00124     copy_to_textures();
00125   }
00126 
00127   _gsg->end_frame(current_thread);
00128 
00129   if (mode == FM_render) {
00130     trigger_flip();
00131     clear_cube_map_selection();
00132   }
00133 }
00134 
00135 ////////////////////////////////////////////////////////////////////
00136 //     Function: glxGraphicsPixmap::close_buffer
00137 //       Access: Protected, Virtual
00138 //  Description: Closes the pixmap right now.  Called from the window
00139 //               thread.
00140 ////////////////////////////////////////////////////////////////////
00141 void glxGraphicsPixmap::
00142 close_buffer() {
00143   if (_gsg != (GraphicsStateGuardian *)NULL) {
00144     glXMakeCurrent(_display, None, NULL);
00145     _gsg.clear();
00146   }
00147 
00148   if (_glx_pixmap != None) {
00149     glXDestroyGLXPixmap(_display, _glx_pixmap);
00150     _glx_pixmap = None;
00151   }
00152 
00153   if (_x_pixmap != None) {
00154     XFreePixmap(_display, _x_pixmap);
00155     _x_pixmap = None;
00156   }
00157 
00158   _is_valid = false;
00159 }
00160 
00161 ////////////////////////////////////////////////////////////////////
00162 //     Function: glxGraphicsPixmap::open_buffer
00163 //       Access: Protected, Virtual
00164 //  Description: Opens the pixmap right now.  Called from the window
00165 //               thread.  Returns true if the pixmap is successfully
00166 //               opened, or false if there was a problem.
00167 ////////////////////////////////////////////////////////////////////
00168 bool glxGraphicsPixmap::
00169 open_buffer() {
00170   glxGraphicsPipe *glx_pipe;
00171   DCAST_INTO_R(glx_pipe, _pipe, false);
00172 
00173   // GSG Creation/Initialization
00174   glxGraphicsStateGuardian *glxgsg;
00175   if (_gsg == 0) {
00176     // There is no old gsg.  Create a new one.
00177     glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL);
00178     glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
00179     _gsg = glxgsg;
00180   } else {
00181     // If the old gsg has the wrong pixel format, create a
00182     // new one that shares with the old gsg.
00183     DCAST_INTO_R(glxgsg, _gsg, false);
00184     if (!glxgsg->_context_has_pixmap || 
00185         !glxgsg->get_fb_properties().subsumes(_fb_properties)) {
00186       glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
00187       glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
00188       _gsg = glxgsg;
00189     }
00190   }
00191 
00192   if (!glxgsg->_context_has_pixmap) {
00193     // Hmm, the GSG we created won't work.
00194     return false;
00195   }
00196 
00197   XVisualInfo *visual_info = glxgsg->_visual;
00198   if (visual_info == NULL) {
00199     // No X visual for this fbconfig; how can we create the pixmap?
00200     glxdisplay_cat.error()
00201       << "No X visual: cannot create pixmap.\n";
00202     return false;
00203   }
00204 
00205   _drawable = glx_pipe->get_root();
00206   if (_host != NULL) {
00207     if (_host->is_of_type(glxGraphicsWindow::get_class_type())) {
00208       glxGraphicsWindow *win = DCAST(glxGraphicsWindow, _host);
00209       _drawable = win->get_xwindow();
00210     } else if (_host->is_of_type(glxGraphicsPixmap::get_class_type())) {
00211       glxGraphicsPixmap *pix = DCAST(glxGraphicsPixmap, _host);
00212       _drawable = pix->_drawable;
00213     }
00214   }
00215 
00216   _x_pixmap = XCreatePixmap(_display, _drawable, 
00217                             _x_size, _y_size, visual_info->depth);
00218   if (_x_pixmap == None) {
00219     glxdisplay_cat.error()
00220       << "Failed to create X pixmap.\n";
00221     close_buffer();
00222     return false;
00223   }
00224 
00225   if (glxgsg->_fbconfig) {
00226     // Use the FBConfig to create the pixmap.
00227     _glx_pixmap = glxgsg->_glXCreatePixmap(_display, glxgsg->_fbconfig, _x_pixmap, NULL);
00228   } else {
00229     // Use the XVisual to create the pixmap.
00230     _glx_pixmap = glXCreateGLXPixmap(_display, visual_info, _x_pixmap);
00231   }
00232 
00233   if (_glx_pixmap == None) {
00234     glxdisplay_cat.error()
00235       << "Failed to create GLX pixmap.\n";
00236     close_buffer();
00237     return false;
00238   }
00239 
00240   int error_count = x11GraphicsPipe::disable_x_error_messages();
00241   glXMakeCurrent(_display, _glx_pixmap, glxgsg->_context);
00242   if (x11GraphicsPipe::enable_x_error_messages() != error_count) {
00243     // An error was generated during the glXMakeCurrent() call.
00244     // Assume the worst.
00245     close_buffer();
00246     return false;
00247   }
00248 
00249   glxgsg->reset_if_new();
00250   if (!glxgsg->is_valid()) {
00251     close_buffer();
00252     return false;
00253   }
00254   if (!glxgsg->get_fb_properties().verify_hardware_software
00255       (_fb_properties, glxgsg->get_gl_renderer())) {
00256     close_buffer();
00257     return false;
00258   }
00259   _fb_properties = glxgsg->get_fb_properties();
00260   
00261   _is_valid = true;
00262   return true;
00263 }
 All Classes Functions Variables Enumerations