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     for (int i=0; i<count_textures(); i++) {
00095       if (get_rtm_mode(i) == RTM_bind_or_copy) {
00096         _textures[i]._rtm_mode = RTM_copy_texture;
00097       }
00098     }
00099     clear_cube_map_selection();
00100   }
00101   
00102   _gsg->set_current_properties(&get_fb_properties());
00103   return _gsg->begin_frame(current_thread);
00104 }
00105 
00106 ////////////////////////////////////////////////////////////////////
00107 //     Function: glxGraphicsPixmap::end_frame
00108 //       Access: Public, Virtual
00109 //  Description: This function will be called within the draw thread
00110 //               after rendering is completed for a given frame.  It
00111 //               should do whatever finalization is required.
00112 ////////////////////////////////////////////////////////////////////
00113 void glxGraphicsPixmap::
00114 end_frame(FrameMode mode, Thread *current_thread) {
00115   end_frame_spam(mode);
00116   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00117 
00118   if (mode == FM_render) {
00119     copy_to_textures();
00120   }
00121 
00122   _gsg->end_frame(current_thread);
00123 
00124   if (mode == FM_render) {
00125     trigger_flip();
00126     if (_one_shot) {
00127       prepare_for_deletion();
00128     }
00129     clear_cube_map_selection();
00130   }
00131 }
00132 
00133 ////////////////////////////////////////////////////////////////////
00134 //     Function: glxGraphicsPixmap::close_buffer
00135 //       Access: Protected, Virtual
00136 //  Description: Closes the pixmap right now.  Called from the window
00137 //               thread.
00138 ////////////////////////////////////////////////////////////////////
00139 void glxGraphicsPixmap::
00140 close_buffer() {
00141   if (_gsg != (GraphicsStateGuardian *)NULL) {
00142     glXMakeCurrent(_display, None, NULL);
00143     _gsg.clear();
00144     _active = false;
00145   }
00146 
00147   if (_glx_pixmap != None) {
00148     glXDestroyGLXPixmap(_display, _glx_pixmap);
00149     _glx_pixmap = None;
00150   }
00151 
00152   if (_x_pixmap != None) {
00153     XFreePixmap(_display, _x_pixmap);
00154     _x_pixmap = None;
00155   }
00156 
00157   _is_valid = false;
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: glxGraphicsPixmap::open_buffer
00162 //       Access: Protected, Virtual
00163 //  Description: Opens the pixmap right now.  Called from the window
00164 //               thread.  Returns true if the pixmap is successfully
00165 //               opened, or false if there was a problem.
00166 ////////////////////////////////////////////////////////////////////
00167 bool glxGraphicsPixmap::
00168 open_buffer() {
00169   glxGraphicsPipe *glx_pipe;
00170   DCAST_INTO_R(glx_pipe, _pipe, false);
00171 
00172   // GSG Creation/Initialization
00173   glxGraphicsStateGuardian *glxgsg;
00174   if (_gsg == 0) {
00175     // There is no old gsg.  Create a new one.
00176     glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL);
00177     glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
00178     _gsg = glxgsg;
00179   } else {
00180     // If the old gsg has the wrong pixel format, create a
00181     // new one that shares with the old gsg.
00182     DCAST_INTO_R(glxgsg, _gsg, false);
00183     if (!glxgsg->_context_has_pixmap || 
00184         !glxgsg->get_fb_properties().subsumes(_fb_properties)) {
00185       glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
00186       glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
00187       _gsg = glxgsg;
00188     }
00189   }
00190 
00191   if (!glxgsg->_context_has_pixmap) {
00192     // Hmm, the GSG we created won't work.
00193     return false;
00194   }
00195 
00196   XVisualInfo *visual_info = glxgsg->_visual;
00197   if (visual_info == NULL) {
00198     // No X visual for this fbconfig; how can we create the pixmap?
00199     glxdisplay_cat.error()
00200       << "No X visual: cannot create pixmap.\n";
00201     return false;
00202   }
00203 
00204   _drawable = glx_pipe->get_root();
00205   if (_host != NULL) {
00206     if (_host->is_of_type(glxGraphicsWindow::get_class_type())) {
00207       glxGraphicsWindow *win = DCAST(glxGraphicsWindow, _host);
00208       _drawable = win->get_xwindow();
00209     } else if (_host->is_of_type(glxGraphicsPixmap::get_class_type())) {
00210       glxGraphicsPixmap *pix = DCAST(glxGraphicsPixmap, _host);
00211       _drawable = pix->_drawable;
00212     }
00213   }
00214 
00215   _x_pixmap = XCreatePixmap(_display, _drawable, 
00216                             _x_size, _y_size, visual_info->depth);
00217   if (_x_pixmap == None) {
00218     glxdisplay_cat.error()
00219       << "Failed to create X pixmap.\n";
00220     close_buffer();
00221     return false;
00222   }
00223 
00224   if (glxgsg->_fbconfig) {
00225     // Use the FBConfig to create the pixmap.
00226     _glx_pixmap = glxgsg->_glXCreatePixmap(_display, glxgsg->_fbconfig, _x_pixmap, NULL);
00227   } else {
00228     // Use the XVisual to create the pixmap.
00229     _glx_pixmap = glXCreateGLXPixmap(_display, visual_info, _x_pixmap);
00230   }
00231 
00232   if (_glx_pixmap == None) {
00233     glxdisplay_cat.error()
00234       << "Failed to create GLX pixmap.\n";
00235     close_buffer();
00236     return false;
00237   }
00238 
00239   int error_count = x11GraphicsPipe::disable_x_error_messages();
00240   glXMakeCurrent(_display, _glx_pixmap, glxgsg->_context);
00241   if (x11GraphicsPipe::enable_x_error_messages() != error_count) {
00242     // An error was generated during the glXMakeCurrent() call.
00243     // Assume the worst.
00244     close_buffer();
00245     return false;
00246   }
00247 
00248   glxgsg->reset_if_new();
00249   if (!glxgsg->is_valid()) {
00250     close_buffer();
00251     return false;
00252   }
00253   if (!glxgsg->get_fb_properties().verify_hardware_software
00254       (_fb_properties, glxgsg->get_gl_renderer())) {
00255     close_buffer();
00256     return false;
00257   }
00258   _fb_properties = glxgsg->get_fb_properties();
00259   
00260   _is_valid = true;
00261   return true;
00262 }
 All Classes Functions Variables Enumerations