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