Panda3D

glxGraphicsBuffer.cxx

00001 // Filename: glxGraphicsBuffer.cxx
00002 // Created by:  drose (09Feb04)
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 "glxGraphicsBuffer.h"
00016 #include "glxGraphicsStateGuardian.h"
00017 #include "config_glxdisplay.h"
00018 #include "glxGraphicsPipe.h"
00019 
00020 #include "graphicsPipe.h"
00021 #include "glgsg.h"
00022 #include "pStatTimer.h"
00023 
00024 TypeHandle glxGraphicsBuffer::_type_handle;
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: glxGraphicsBuffer::Constructor
00028 //       Access: Public
00029 //  Description:
00030 ////////////////////////////////////////////////////////////////////
00031 glxGraphicsBuffer::
00032 glxGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe, 
00033                   const string &name,
00034                   const FrameBufferProperties &fb_prop,
00035                   const WindowProperties &win_prop,
00036                   int flags,
00037                   GraphicsStateGuardian *gsg,
00038                   GraphicsOutput *host) :
00039   GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00040 {
00041   glxGraphicsPipe *glx_pipe;
00042   DCAST_INTO_V(glx_pipe, _pipe);
00043   _display = glx_pipe->get_display();
00044   _pbuffer = None;
00045 
00046   // Since the pbuffer never gets flipped, we get screenshots from the
00047   // same buffer we draw into.
00048   _screenshot_buffer_type = _draw_buffer_type;
00049 }
00050 
00051 ////////////////////////////////////////////////////////////////////
00052 //     Function: glxGraphicsBuffer::Destructor
00053 //       Access: Public, Virtual
00054 //  Description:
00055 ////////////////////////////////////////////////////////////////////
00056 glxGraphicsBuffer::
00057 ~glxGraphicsBuffer() {
00058   nassertv(_pbuffer == None);
00059 }
00060 
00061 ////////////////////////////////////////////////////////////////////
00062 //     Function: glxGraphicsBuffer::begin_frame
00063 //       Access: Public, Virtual
00064 //  Description: This function will be called within the draw thread
00065 //               before beginning rendering for a given frame.  It
00066 //               should do whatever setup is required, and return true
00067 //               if the frame should be rendered, or false if it
00068 //               should be skipped.
00069 ////////////////////////////////////////////////////////////////////
00070 bool glxGraphicsBuffer::
00071 begin_frame(FrameMode mode, Thread *current_thread) {
00072   PStatTimer timer(_make_current_pcollector, current_thread);
00073 
00074   begin_frame_spam(mode);
00075   if (_gsg == (GraphicsStateGuardian *)NULL ||
00076       _pbuffer == None) {
00077     return false;
00078   }
00079 
00080   glxGraphicsStateGuardian *glxgsg;
00081   DCAST_INTO_R(glxgsg, _gsg, false);
00082   glXMakeCurrent(_display, _pbuffer, glxgsg->_context);
00083 
00084   // Now that we have made the context current to a window, we can
00085   // reset the GSG state if this is the first time it has been used.
00086   // (We can't just call reset() when we construct the GSG, because
00087   // reset() requires having a current context.)
00088   glxgsg->reset_if_new();
00089 
00090   if (mode == FM_render) {
00091     CDLockedReader cdata(_cycler);
00092     for (size_t i = 0; i != cdata->_textures.size(); ++i) {
00093       const RenderTexture &rt = cdata->_textures[i];
00094       RenderTextureMode rtm_mode = rt._rtm_mode;
00095       if (rtm_mode == RTM_bind_or_copy) {
00096         CDWriter cdataw(_cycler, cdata, false);
00097         nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
00098         cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
00099       }
00100     }
00101     clear_cube_map_selection();
00102   }
00103   
00104   _gsg->set_current_properties(&get_fb_properties());
00105   return _gsg->begin_frame(current_thread);
00106 }
00107 
00108 ////////////////////////////////////////////////////////////////////
00109 //     Function: glxGraphicsBuffer::end_frame
00110 //       Access: Public, Virtual
00111 //  Description: This function will be called within the draw thread
00112 //               after rendering is completed for a given frame.  It
00113 //               should do whatever finalization is required.
00114 ////////////////////////////////////////////////////////////////////
00115 void glxGraphicsBuffer::
00116 end_frame(FrameMode mode, Thread *current_thread) {
00117   end_frame_spam(mode);
00118   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00119 
00120   if (mode == FM_render) {
00121     copy_to_textures();
00122   }
00123 
00124   _gsg->end_frame(current_thread);
00125 
00126   if (mode == FM_render) {
00127     trigger_flip();
00128     clear_cube_map_selection();
00129   }
00130 }
00131 
00132 ////////////////////////////////////////////////////////////////////
00133 //     Function: glxGraphicsBuffer::close_buffer
00134 //       Access: Protected, Virtual
00135 //  Description: Closes the buffer right now.  Called from the window
00136 //               thread.
00137 ////////////////////////////////////////////////////////////////////
00138 void glxGraphicsBuffer::
00139 close_buffer() {
00140   if (_gsg != (GraphicsStateGuardian *)NULL) {
00141     glXMakeCurrent(_display, None, NULL);
00142 
00143     if (_pbuffer != None) {
00144       glxGraphicsStateGuardian *glxgsg;
00145       DCAST_INTO_V(glxgsg, _gsg);
00146       glxgsg->_glXDestroyPbuffer(_display, _pbuffer);
00147       _pbuffer = None;
00148     }
00149     
00150     _gsg.clear();
00151   }
00152 
00153   _pbuffer = None;
00154   _is_valid = false;
00155 }
00156 
00157 ////////////////////////////////////////////////////////////////////
00158 //     Function: glxGraphicsBuffer::open_buffer
00159 //       Access: Protected, Virtual
00160 //  Description: Opens the buffer right now.  Called from the window
00161 //               thread.  Returns true if the buffer is successfully
00162 //               opened, or false if there was a problem.
00163 ////////////////////////////////////////////////////////////////////
00164 bool glxGraphicsBuffer::
00165 open_buffer() {
00166   glxGraphicsPipe *glx_pipe;
00167   DCAST_INTO_R(glx_pipe, _pipe, false);
00168 
00169   // GSG Creation/Initialization
00170   glxGraphicsStateGuardian *glxgsg;
00171   if (_gsg == 0) {
00172     // There is no old gsg.  Create a new one.
00173     glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL);
00174     glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true, false);
00175     _gsg = glxgsg;
00176   } else {
00177     // If the old gsg has the wrong pixel format, create a
00178     // new one that shares with the old gsg.
00179     DCAST_INTO_R(glxgsg, _gsg, false);
00180 
00181     if (!glxgsg->_context_has_pbuffer || 
00182         !glxgsg->get_fb_properties().subsumes(_fb_properties)) {
00183       // We need a new pixel format, and hence a new GSG.
00184       glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
00185       glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true, false);
00186       _gsg = glxgsg;
00187     }
00188   }
00189   
00190   if (glxgsg->_fbconfig == None || glxgsg->_context_has_pbuffer) {
00191     // If we didn't use an fbconfig to create the GSG, or it doesn't
00192     // support buffers, we can't create a PBuffer.
00193     return false;
00194   }
00195 
00196   nassertr(glxgsg->_supports_pbuffer, false);
00197 
00198   static const int max_attrib_list = 32;
00199   int attrib_list[max_attrib_list];
00200   int n = 0;
00201 
00202   if (glxgsg->_uses_sgix_pbuffer) {
00203     // The SGI version passed in the size in the parameter list.
00204     nassertr(n < max_attrib_list, false);
00205     attrib_list[n] = (int)None;
00206     _pbuffer = glxgsg->_glXCreateGLXPbufferSGIX(glxgsg->_display, glxgsg->_fbconfig,
00207                                                 _x_size, _y_size, attrib_list);
00208   } else {
00209     // The official GLX 1.3 version passes in the size in the attrib
00210     // list.
00211     attrib_list[n++] = GLX_PBUFFER_WIDTH;
00212     attrib_list[n++] = _x_size;
00213     attrib_list[n++] = GLX_PBUFFER_HEIGHT;
00214     attrib_list[n++] = _y_size;
00215     
00216     nassertr(n < max_attrib_list, false);
00217     attrib_list[n] = (int)None;
00218     _pbuffer = glxgsg->_glXCreatePbuffer(glxgsg->_display, glxgsg->_fbconfig,
00219                                          attrib_list);
00220   }
00221 
00222   if (_pbuffer == None) {
00223     glxdisplay_cat.error()
00224       << "failed to create GLX pbuffer.\n";
00225     return false;
00226   }
00227 
00228   glXMakeCurrent(_display, _pbuffer, glxgsg->_context);
00229   glxgsg->reset_if_new();
00230   if (!glxgsg->is_valid()) {
00231     close_buffer();
00232     return false;
00233   }
00234   if (!glxgsg->get_fb_properties().verify_hardware_software
00235       (_fb_properties, glxgsg->get_gl_renderer())) {
00236     close_buffer();
00237     return false;
00238   }
00239   _fb_properties = glxgsg->get_fb_properties();
00240   
00241   _is_valid = true;
00242   return true;
00243 }
 All Classes Functions Variables Enumerations