eglGraphicsBuffer.cxx

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 }