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 CDLockedReader cdata(_cycler); 00092 for (size_t i = 0; i != cdata->_textures.size(); ++i) { 00093 const RenderTexture &rt = cdata->_textures[i]; 00094 RenderTextureMode rtm_mode = rt._rtm_mode; 00095 if (rtm_mode == RTM_bind_or_copy) { 00096 CDWriter cdataw(_cycler, cdata, false); 00097 nassertr(cdata->_textures.size() == cdataw->_textures.size(), false); 00098 cdataw->_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: eglGraphicsBuffer::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 eglGraphicsBuffer:: 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 clear_cube_map_selection(); 00129 } 00130 } 00131 00132 //////////////////////////////////////////////////////////////////// 00133 // Function: eglGraphicsBuffer::close_buffer 00134 // Access: Protected, Virtual 00135 // Description: Closes the buffer right now. Called from the window 00136 // thread. 00137 //////////////////////////////////////////////////////////////////// 00138 void eglGraphicsBuffer:: 00139 close_buffer() { 00140 if (_gsg != (GraphicsStateGuardian *)NULL) { 00141 eglGraphicsStateGuardian *eglgsg; 00142 DCAST_INTO_V(eglgsg, _gsg); 00143 if (!eglMakeCurrent(eglgsg->_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { 00144 egldisplay_cat.error() << "Failed to call eglMakeCurrent: " 00145 << get_egl_error_string(eglGetError()) << "\n"; 00146 } 00147 _gsg.clear(); 00148 00149 if (_pbuffer != EGL_NO_SURFACE) { 00150 if (!eglDestroySurface(_egl_display, _pbuffer)) { 00151 egldisplay_cat.error() << "Failed to destroy surface: " 00152 << get_egl_error_string(eglGetError()) << "\n"; 00153 } 00154 _pbuffer = EGL_NO_SURFACE; 00155 } 00156 } 00157 00158 _is_valid = false; 00159 } 00160 00161 //////////////////////////////////////////////////////////////////// 00162 // Function: eglGraphicsBuffer::open_buffer 00163 // Access: Protected, Virtual 00164 // Description: Opens the buffer right now. Called from the window 00165 // thread. Returns true if the buffer is successfully 00166 // opened, or false if there was a problem. 00167 //////////////////////////////////////////////////////////////////// 00168 bool eglGraphicsBuffer:: 00169 open_buffer() { 00170 eglGraphicsPipe *egl_pipe; 00171 DCAST_INTO_R(egl_pipe, _pipe, false); 00172 00173 // GSG Creation/Initialization 00174 eglGraphicsStateGuardian *eglgsg; 00175 if (_gsg == 0) { 00176 // There is no old gsg. Create a new one. 00177 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL); 00178 eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false); 00179 _gsg = eglgsg; 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(eglgsg, _gsg, false); 00184 if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) { 00185 eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg); 00186 eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false); 00187 _gsg = eglgsg; 00188 } 00189 } 00190 00191 if (eglgsg->_fbconfig == None) { 00192 // If we didn't use an fbconfig to create the GSG, we can't create 00193 // a PBuffer. 00194 return false; 00195 } 00196 00197 int attrib_list[] = { 00198 EGL_WIDTH, _x_size, 00199 EGL_HEIGHT, _y_size, 00200 EGL_NONE 00201 }; 00202 00203 _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list); 00204 00205 if (_pbuffer == EGL_NO_SURFACE) { 00206 egldisplay_cat.error() 00207 << "Failed to create EGL pbuffer surface: " 00208 << get_egl_error_string(eglGetError()) << "\n"; 00209 return false; 00210 } 00211 00212 if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) { 00213 egldisplay_cat.error() << "Failed to call eglMakeCurrent: " 00214 << get_egl_error_string(eglGetError()) << "\n"; 00215 } 00216 eglgsg->reset_if_new(); 00217 if (!eglgsg->is_valid()) { 00218 close_buffer(); 00219 return false; 00220 } 00221 if (!eglgsg->get_fb_properties().verify_hardware_software 00222 (_fb_properties, eglgsg->get_gl_renderer())) { 00223 close_buffer(); 00224 return false; 00225 } 00226 _fb_properties = eglgsg->get_fb_properties(); 00227 00228 _is_valid = true; 00229 return true; 00230 }