Panda3D
|
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 }