Panda3D
|
00001 // Filename: eglGraphicsPixmap.cxx 00002 // Created by: pro-rsoft (13Jun09) 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 "eglGraphicsPixmap.h" 00016 #include "eglGraphicsWindow.h" 00017 #include "eglGraphicsStateGuardian.h" 00018 #include "config_egldisplay.h" 00019 #include "eglGraphicsPipe.h" 00020 00021 #include "graphicsPipe.h" 00022 #include "pStatTimer.h" 00023 00024 TypeHandle eglGraphicsPixmap::_type_handle; 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: eglGraphicsPixmap::Constructor 00028 // Access: Public 00029 // Description: 00030 //////////////////////////////////////////////////////////////////// 00031 eglGraphicsPixmap:: 00032 eglGraphicsPixmap(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 eglGraphicsPipe *egl_pipe; 00042 DCAST_INTO_V(egl_pipe, _pipe); 00043 _display = egl_pipe->get_display(); 00044 _egl_display = egl_pipe->_egl_display; 00045 _drawable = None; 00046 _x_pixmap = None; 00047 _egl_surface = EGL_NO_SURFACE; 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: eglGraphicsPixmap::Destructor 00056 // Access: Public, Virtual 00057 // Description: 00058 //////////////////////////////////////////////////////////////////// 00059 eglGraphicsPixmap:: 00060 ~eglGraphicsPixmap() { 00061 nassertv(_x_pixmap == None && _egl_surface == EGL_NO_SURFACE); 00062 } 00063 00064 //////////////////////////////////////////////////////////////////// 00065 // Function: eglGraphicsPixmap::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 eglGraphicsPixmap:: 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 return false; 00080 } 00081 00082 eglGraphicsStateGuardian *eglgsg; 00083 DCAST_INTO_R(eglgsg, _gsg, false); 00084 if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context)) { 00085 egldisplay_cat.error() << "Failed to call eglMakeCurrent: " 00086 << get_egl_error_string(eglGetError()) << "\n"; 00087 } 00088 00089 // Now that we have made the context current to a window, we can 00090 // reset the GSG state if this is the first time it has been used. 00091 // (We can't just call reset() when we construct the GSG, because 00092 // reset() requires having a current context.) 00093 eglgsg->reset_if_new(); 00094 00095 if (mode == FM_render) { 00096 CDLockedReader cdata(_cycler); 00097 for (size_t i = 0; i != cdata->_textures.size(); ++i) { 00098 const RenderTexture &rt = cdata->_textures[i]; 00099 RenderTextureMode rtm_mode = rt._rtm_mode; 00100 if (rtm_mode == RTM_bind_or_copy) { 00101 CDWriter cdataw(_cycler, cdata, false); 00102 nassertr(cdata->_textures.size() == cdataw->_textures.size(), false); 00103 cdataw->_textures[i]._rtm_mode = RTM_copy_texture; 00104 } 00105 } 00106 clear_cube_map_selection(); 00107 } 00108 00109 _gsg->set_current_properties(&get_fb_properties()); 00110 return _gsg->begin_frame(current_thread); 00111 } 00112 00113 //////////////////////////////////////////////////////////////////// 00114 // Function: eglGraphicsPixmap::end_frame 00115 // Access: Public, Virtual 00116 // Description: This function will be called within the draw thread 00117 // after rendering is completed for a given frame. It 00118 // should do whatever finalization is required. 00119 //////////////////////////////////////////////////////////////////// 00120 void eglGraphicsPixmap:: 00121 end_frame(FrameMode mode, Thread *current_thread) { 00122 end_frame_spam(mode); 00123 nassertv(_gsg != (GraphicsStateGuardian *)NULL); 00124 00125 if (mode == FM_render) { 00126 copy_to_textures(); 00127 } 00128 00129 _gsg->end_frame(current_thread); 00130 00131 if (mode == FM_render) { 00132 trigger_flip(); 00133 clear_cube_map_selection(); 00134 } 00135 } 00136 00137 //////////////////////////////////////////////////////////////////// 00138 // Function: eglGraphicsPixmap::close_buffer 00139 // Access: Protected, Virtual 00140 // Description: Closes the pixmap right now. Called from the window 00141 // thread. 00142 //////////////////////////////////////////////////////////////////// 00143 void eglGraphicsPixmap:: 00144 close_buffer() { 00145 if (_gsg != (GraphicsStateGuardian *)NULL) { 00146 if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { 00147 egldisplay_cat.error() << "Failed to call eglMakeCurrent: " 00148 << get_egl_error_string(eglGetError()) << "\n"; 00149 } 00150 _gsg.clear(); 00151 } 00152 00153 if (_egl_surface != EGL_NO_SURFACE) { 00154 if (!eglDestroySurface(_egl_display, _egl_surface)) { 00155 egldisplay_cat.error() << "Failed to destroy surface: " 00156 << get_egl_error_string(eglGetError()) << "\n"; 00157 } 00158 _egl_surface = EGL_NO_SURFACE; 00159 } 00160 00161 if (_x_pixmap != None) { 00162 XFreePixmap(_display, _x_pixmap); 00163 _x_pixmap = None; 00164 } 00165 00166 _is_valid = false; 00167 } 00168 00169 //////////////////////////////////////////////////////////////////// 00170 // Function: eglGraphicsPixmap::open_buffer 00171 // Access: Protected, Virtual 00172 // Description: Opens the pixmap right now. Called from the window 00173 // thread. Returns true if the pixmap is successfully 00174 // opened, or false if there was a problem. 00175 //////////////////////////////////////////////////////////////////// 00176 bool eglGraphicsPixmap:: 00177 open_buffer() { 00178 eglGraphicsPipe *egl_pipe; 00179 DCAST_INTO_R(egl_pipe, _pipe, false); 00180 00181 // GSG Creation/Initialization 00182 eglGraphicsStateGuardian *eglgsg; 00183 if (_gsg == 0) { 00184 // There is no old gsg. Create a new one. 00185 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL); 00186 eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true); 00187 _gsg = eglgsg; 00188 } else { 00189 // If the old gsg has the wrong pixel format, create a 00190 // new one that shares with the old gsg. 00191 DCAST_INTO_R(eglgsg, _gsg, false); 00192 if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) { 00193 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg); 00194 eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true); 00195 _gsg = eglgsg; 00196 } 00197 } 00198 00199 if (eglgsg->_fbconfig == None) { 00200 // If we didn't use an fbconfig to create the GSG, we can't create 00201 // a PBuffer. 00202 return false; 00203 } 00204 00205 XVisualInfo *visual_info = eglgsg->_visual; 00206 if (visual_info == NULL) { 00207 // No X visual for this fbconfig; how can we create the pixmap? 00208 egldisplay_cat.error() 00209 << "No X visual: cannot create pixmap.\n"; 00210 return false; 00211 } 00212 00213 _drawable = egl_pipe->get_root(); 00214 if (_host != NULL) { 00215 if (_host->is_of_type(eglGraphicsWindow::get_class_type())) { 00216 eglGraphicsWindow *win = DCAST(eglGraphicsWindow, _host); 00217 _drawable = win->get_xwindow(); 00218 } else if (_host->is_of_type(eglGraphicsPixmap::get_class_type())) { 00219 eglGraphicsPixmap *pix = DCAST(eglGraphicsPixmap, _host); 00220 _drawable = pix->_drawable; 00221 } 00222 } 00223 00224 _x_pixmap = XCreatePixmap(_display, _drawable, 00225 _x_size, _y_size, visual_info->depth); 00226 if (_x_pixmap == None) { 00227 egldisplay_cat.error() 00228 << "Failed to create X pixmap.\n"; 00229 close_buffer(); 00230 return false; 00231 } 00232 00233 nassertr(eglgsg->_fbconfig, false); 00234 _egl_surface = eglCreatePixmapSurface(_egl_display, eglgsg->_fbconfig, (NativePixmapType) _x_pixmap, NULL); 00235 00236 if (_egl_surface == EGL_NO_SURFACE) { 00237 egldisplay_cat.error() 00238 << "Failed to create EGL pixmap surface:" 00239 << get_egl_error_string(eglGetError()) << "\n"; 00240 close_buffer(); 00241 return false; 00242 } 00243 00244 eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context); 00245 eglgsg->reset_if_new(); 00246 if (!eglgsg->is_valid()) { 00247 close_buffer(); 00248 return false; 00249 } 00250 if (!eglgsg->get_fb_properties().verify_hardware_software 00251 (_fb_properties, eglgsg->get_gl_renderer())) { 00252 close_buffer(); 00253 return false; 00254 } 00255 _fb_properties = eglgsg->get_fb_properties(); 00256 00257 _is_valid = true; 00258 return true; 00259 }