Panda3D

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     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 }
 All Classes Functions Variables Enumerations