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 for (int i=0; i<count_textures(); i++) { 00097 if (get_rtm_mode(i) == RTM_bind_or_copy) { 00098 _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: eglGraphicsPixmap::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 eglGraphicsPixmap:: 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 if (_one_shot) { 00129 prepare_for_deletion(); 00130 } 00131 clear_cube_map_selection(); 00132 } 00133 } 00134 00135 //////////////////////////////////////////////////////////////////// 00136 // Function: eglGraphicsPixmap::close_buffer 00137 // Access: Protected, Virtual 00138 // Description: Closes the pixmap right now. Called from the window 00139 // thread. 00140 //////////////////////////////////////////////////////////////////// 00141 void eglGraphicsPixmap:: 00142 close_buffer() { 00143 if (_gsg != (GraphicsStateGuardian *)NULL) { 00144 if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { 00145 egldisplay_cat.error() << "Failed to call eglMakeCurrent: " 00146 << get_egl_error_string(eglGetError()) << "\n"; 00147 } 00148 _gsg.clear(); 00149 _active = false; 00150 } 00151 00152 if (_egl_surface != EGL_NO_SURFACE) { 00153 if (!eglDestroySurface(_egl_display, _egl_surface)) { 00154 egldisplay_cat.error() << "Failed to destroy surface: " 00155 << get_egl_error_string(eglGetError()) << "\n"; 00156 } 00157 _egl_surface = EGL_NO_SURFACE; 00158 } 00159 00160 if (_x_pixmap != None) { 00161 XFreePixmap(_display, _x_pixmap); 00162 _x_pixmap = None; 00163 } 00164 00165 _is_valid = false; 00166 } 00167 00168 //////////////////////////////////////////////////////////////////// 00169 // Function: eglGraphicsPixmap::open_buffer 00170 // Access: Protected, Virtual 00171 // Description: Opens the pixmap right now. Called from the window 00172 // thread. Returns true if the pixmap is successfully 00173 // opened, or false if there was a problem. 00174 //////////////////////////////////////////////////////////////////// 00175 bool eglGraphicsPixmap:: 00176 open_buffer() { 00177 eglGraphicsPipe *egl_pipe; 00178 DCAST_INTO_R(egl_pipe, _pipe, false); 00179 00180 // GSG Creation/Initialization 00181 eglGraphicsStateGuardian *eglgsg; 00182 if (_gsg == 0) { 00183 // There is no old gsg. Create a new one. 00184 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL); 00185 eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true); 00186 _gsg = eglgsg; 00187 } else { 00188 // If the old gsg has the wrong pixel format, create a 00189 // new one that shares with the old gsg. 00190 DCAST_INTO_R(eglgsg, _gsg, false); 00191 if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) { 00192 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg); 00193 eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true); 00194 _gsg = eglgsg; 00195 } 00196 } 00197 00198 if (eglgsg->_fbconfig == None) { 00199 // If we didn't use an fbconfig to create the GSG, we can't create 00200 // a PBuffer. 00201 return false; 00202 } 00203 00204 XVisualInfo *visual_info = eglgsg->_visual; 00205 if (visual_info == NULL) { 00206 // No X visual for this fbconfig; how can we create the pixmap? 00207 egldisplay_cat.error() 00208 << "No X visual: cannot create pixmap.\n"; 00209 return false; 00210 } 00211 00212 _drawable = egl_pipe->get_root(); 00213 if (_host != NULL) { 00214 if (_host->is_of_type(eglGraphicsWindow::get_class_type())) { 00215 eglGraphicsWindow *win = DCAST(eglGraphicsWindow, _host); 00216 _drawable = win->get_xwindow(); 00217 } else if (_host->is_of_type(eglGraphicsPixmap::get_class_type())) { 00218 eglGraphicsPixmap *pix = DCAST(eglGraphicsPixmap, _host); 00219 _drawable = pix->_drawable; 00220 } 00221 } 00222 00223 _x_pixmap = XCreatePixmap(_display, _drawable, 00224 _x_size, _y_size, visual_info->depth); 00225 if (_x_pixmap == None) { 00226 egldisplay_cat.error() 00227 << "Failed to create X pixmap.\n"; 00228 close_buffer(); 00229 return false; 00230 } 00231 00232 nassertr(eglgsg->_fbconfig, false); 00233 _egl_surface = eglCreatePixmapSurface(_egl_display, eglgsg->_fbconfig, (NativePixmapType) _x_pixmap, NULL); 00234 00235 if (_egl_surface == EGL_NO_SURFACE) { 00236 egldisplay_cat.error() 00237 << "Failed to create EGL pixmap surface:" 00238 << get_egl_error_string(eglGetError()) << "\n"; 00239 close_buffer(); 00240 return false; 00241 } 00242 00243 eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context); 00244 eglgsg->reset_if_new(); 00245 if (!eglgsg->is_valid()) { 00246 close_buffer(); 00247 return false; 00248 } 00249 if (!eglgsg->get_fb_properties().verify_hardware_software 00250 (_fb_properties, eglgsg->get_gl_renderer())) { 00251 close_buffer(); 00252 return false; 00253 } 00254 _fb_properties = eglgsg->get_fb_properties(); 00255 00256 _is_valid = true; 00257 return true; 00258 }