Panda3D
|
00001 // Filename: eglGraphicsBuffer.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 "eglGraphicsBuffer.h" 00016 #include "eglGraphicsStateGuardian.h" 00017 #include "config_egldisplay.h" 00018 #include "eglGraphicsPipe.h" 00019 00020 #include "graphicsPipe.h" 00021 #include "pStatTimer.h" 00022 00023 TypeHandle eglGraphicsBuffer::_type_handle; 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: eglGraphicsBuffer::Constructor 00027 // Access: Public 00028 // Description: 00029 //////////////////////////////////////////////////////////////////// 00030 eglGraphicsBuffer:: 00031 eglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe, 00032 const string &name, 00033 const FrameBufferProperties &fb_prop, 00034 const WindowProperties &win_prop, 00035 int flags, 00036 GraphicsStateGuardian *gsg, 00037 GraphicsOutput *host) : 00038 GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host) 00039 { 00040 eglGraphicsPipe *egl_pipe; 00041 DCAST_INTO_V(egl_pipe, _pipe); 00042 _pbuffer = EGL_NO_SURFACE; 00043 00044 // Since the pbuffer never gets flipped, we get screenshots from the 00045 // same buffer we draw into. 00046 _screenshot_buffer_type = _draw_buffer_type; 00047 } 00048 00049 //////////////////////////////////////////////////////////////////// 00050 // Function: eglGraphicsBuffer::Destructor 00051 // Access: Public, Virtual 00052 // Description: 00053 //////////////////////////////////////////////////////////////////// 00054 eglGraphicsBuffer:: 00055 ~eglGraphicsBuffer() { 00056 nassertv(_pbuffer == EGL_NO_SURFACE); 00057 } 00058 00059 //////////////////////////////////////////////////////////////////// 00060 // Function: eglGraphicsBuffer::begin_frame 00061 // Access: Public, Virtual 00062 // Description: This function will be called within the draw thread 00063 // before beginning rendering for a given frame. It 00064 // should do whatever setup is required, and return true 00065 // if the frame should be rendered, or false if it 00066 // should be skipped. 00067 //////////////////////////////////////////////////////////////////// 00068 bool eglGraphicsBuffer:: 00069 begin_frame(FrameMode mode, Thread *current_thread) { 00070 PStatTimer timer(_make_current_pcollector, current_thread); 00071 00072 begin_frame_spam(mode); 00073 if (_gsg == (GraphicsStateGuardian *)NULL) { 00074 return false; 00075 } 00076 00077 eglGraphicsStateGuardian *eglgsg; 00078 DCAST_INTO_R(eglgsg, _gsg, false); 00079 if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) { 00080 egldisplay_cat.error() << "Failed to call eglMakeCurrent: " 00081 << get_egl_error_string(eglGetError()) << "\n"; 00082 } 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 eglgsg->reset_if_new(); 00089 00090 if (mode == FM_render) { 00091 for (int i=0; i<count_textures(); i++) { 00092 if (get_rtm_mode(i) == RTM_bind_or_copy) { 00093 _textures[i]._rtm_mode = RTM_copy_texture; 00094 } 00095 } 00096 clear_cube_map_selection(); 00097 } 00098 00099 _gsg->set_current_properties(&get_fb_properties()); 00100 return _gsg->begin_frame(current_thread); 00101 } 00102 00103 //////////////////////////////////////////////////////////////////// 00104 // Function: eglGraphicsBuffer::end_frame 00105 // Access: Public, Virtual 00106 // Description: This function will be called within the draw thread 00107 // after rendering is completed for a given frame. It 00108 // should do whatever finalization is required. 00109 //////////////////////////////////////////////////////////////////// 00110 void eglGraphicsBuffer:: 00111 end_frame(FrameMode mode, Thread *current_thread) { 00112 end_frame_spam(mode); 00113 nassertv(_gsg != (GraphicsStateGuardian *)NULL); 00114 00115 if (mode == FM_render) { 00116 copy_to_textures(); 00117 } 00118 00119 _gsg->end_frame(current_thread); 00120 00121 if (mode == FM_render) { 00122 trigger_flip(); 00123 if (_one_shot) { 00124 prepare_for_deletion(); 00125 } 00126 clear_cube_map_selection(); 00127 } 00128 } 00129 00130 //////////////////////////////////////////////////////////////////// 00131 // Function: eglGraphicsBuffer::close_buffer 00132 // Access: Protected, Virtual 00133 // Description: Closes the buffer right now. Called from the window 00134 // thread. 00135 //////////////////////////////////////////////////////////////////// 00136 void eglGraphicsBuffer:: 00137 close_buffer() { 00138 if (_gsg != (GraphicsStateGuardian *)NULL) { 00139 eglGraphicsStateGuardian *eglgsg; 00140 DCAST_INTO_V(eglgsg, _gsg); 00141 if (!eglMakeCurrent(eglgsg->_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { 00142 egldisplay_cat.error() << "Failed to call eglMakeCurrent: " 00143 << get_egl_error_string(eglGetError()) << "\n"; 00144 } 00145 _gsg.clear(); 00146 _active = false; 00147 00148 if (_pbuffer != EGL_NO_SURFACE) { 00149 if (!eglDestroySurface(_egl_display, _pbuffer)) { 00150 egldisplay_cat.error() << "Failed to destroy surface: " 00151 << get_egl_error_string(eglGetError()) << "\n"; 00152 } 00153 _pbuffer = EGL_NO_SURFACE; 00154 } 00155 } 00156 00157 _is_valid = false; 00158 } 00159 00160 //////////////////////////////////////////////////////////////////// 00161 // Function: eglGraphicsBuffer::open_buffer 00162 // Access: Protected, Virtual 00163 // Description: Opens the buffer right now. Called from the window 00164 // thread. Returns true if the buffer is successfully 00165 // opened, or false if there was a problem. 00166 //////////////////////////////////////////////////////////////////// 00167 bool eglGraphicsBuffer:: 00168 open_buffer() { 00169 eglGraphicsPipe *egl_pipe; 00170 DCAST_INTO_R(egl_pipe, _pipe, false); 00171 00172 // GSG Creation/Initialization 00173 eglGraphicsStateGuardian *eglgsg; 00174 if (_gsg == 0) { 00175 // There is no old gsg. Create a new one. 00176 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL); 00177 eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false); 00178 _gsg = eglgsg; 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(eglgsg, _gsg, false); 00183 if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) { 00184 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg); 00185 eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false); 00186 _gsg = eglgsg; 00187 } 00188 } 00189 00190 if (eglgsg->_fbconfig == None) { 00191 // If we didn't use an fbconfig to create the GSG, we can't create 00192 // a PBuffer. 00193 return false; 00194 } 00195 00196 int attrib_list[] = { 00197 EGL_WIDTH, _x_size, 00198 EGL_HEIGHT, _y_size, 00199 EGL_NONE 00200 }; 00201 00202 _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list); 00203 00204 if (_pbuffer == EGL_NO_SURFACE) { 00205 egldisplay_cat.error() 00206 << "Failed to create EGL pbuffer surface: " 00207 << get_egl_error_string(eglGetError()) << "\n"; 00208 return false; 00209 } 00210 00211 if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) { 00212 egldisplay_cat.error() << "Failed to call eglMakeCurrent: " 00213 << get_egl_error_string(eglGetError()) << "\n"; 00214 } 00215 eglgsg->reset_if_new(); 00216 if (!eglgsg->is_valid()) { 00217 close_buffer(); 00218 return false; 00219 } 00220 if (!eglgsg->get_fb_properties().verify_hardware_software 00221 (_fb_properties, eglgsg->get_gl_renderer())) { 00222 close_buffer(); 00223 return false; 00224 } 00225 _fb_properties = eglgsg->get_fb_properties(); 00226 00227 _is_valid = true; 00228 return true; 00229 }