eglGraphicsPixmap.cxx

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     CDLockedReader cdata(_cycler);
00097     for (size_t i = 0; i != cdata->_textures.size(); ++i) {
00098       const RenderTexture &rt = cdata->_textures[i];
00099       RenderTextureMode rtm_mode = rt._rtm_mode;
00100       if (rtm_mode == RTM_bind_or_copy) {
00101         CDWriter cdataw(_cycler, cdata, false);
00102         nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
00103         cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
00104       }
00105     }
00106     clear_cube_map_selection();
00107   }
00108   
00109   _gsg->set_current_properties(&get_fb_properties());
00110   return _gsg->begin_frame(current_thread);
00111 }
00112 
00113 ////////////////////////////////////////////////////////////////////
00114 //     Function: eglGraphicsPixmap::end_frame
00115 //       Access: Public, Virtual
00116 //  Description: This function will be called within the draw thread
00117 //               after rendering is completed for a given frame.  It
00118 //               should do whatever finalization is required.
00119 ////////////////////////////////////////////////////////////////////
00120 void eglGraphicsPixmap::
00121 end_frame(FrameMode mode, Thread *current_thread) {
00122   end_frame_spam(mode);
00123   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00124 
00125   if (mode == FM_render) {
00126     copy_to_textures();
00127   }
00128 
00129   _gsg->end_frame(current_thread);
00130 
00131   if (mode == FM_render) {
00132     trigger_flip();
00133     clear_cube_map_selection();
00134   }
00135 }
00136 
00137 ////////////////////////////////////////////////////////////////////
00138 //     Function: eglGraphicsPixmap::close_buffer
00139 //       Access: Protected, Virtual
00140 //  Description: Closes the pixmap right now.  Called from the window
00141 //               thread.
00142 ////////////////////////////////////////////////////////////////////
00143 void eglGraphicsPixmap::
00144 close_buffer() {
00145   if (_gsg != (GraphicsStateGuardian *)NULL) {
00146     if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
00147       egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
00148         << get_egl_error_string(eglGetError()) << "\n";
00149     }
00150     _gsg.clear();
00151   }
00152 
00153   if (_egl_surface != EGL_NO_SURFACE) {
00154     if (!eglDestroySurface(_egl_display, _egl_surface)) {
00155       egldisplay_cat.error() << "Failed to destroy surface: "
00156         << get_egl_error_string(eglGetError()) << "\n";
00157     }
00158     _egl_surface = EGL_NO_SURFACE;
00159   }
00160 
00161   if (_x_pixmap != None) {
00162     XFreePixmap(_display, _x_pixmap);
00163     _x_pixmap = None;
00164   }
00165 
00166   _is_valid = false;
00167 }
00168 
00169 ////////////////////////////////////////////////////////////////////
00170 //     Function: eglGraphicsPixmap::open_buffer
00171 //       Access: Protected, Virtual
00172 //  Description: Opens the pixmap right now.  Called from the window
00173 //               thread.  Returns true if the pixmap is successfully
00174 //               opened, or false if there was a problem.
00175 ////////////////////////////////////////////////////////////////////
00176 bool eglGraphicsPixmap::
00177 open_buffer() {
00178   eglGraphicsPipe *egl_pipe;
00179   DCAST_INTO_R(egl_pipe, _pipe, false);
00180 
00181   // GSG Creation/Initialization
00182   eglGraphicsStateGuardian *eglgsg;
00183   if (_gsg == 0) {
00184     // There is no old gsg.  Create a new one.
00185     eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL);
00186     eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true);
00187     _gsg = eglgsg;
00188   } else {
00189     // If the old gsg has the wrong pixel format, create a
00190     // new one that shares with the old gsg.
00191     DCAST_INTO_R(eglgsg, _gsg, false);
00192     if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
00193       eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
00194       eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true);
00195       _gsg = eglgsg;
00196     }
00197   }
00198   
00199   if (eglgsg->_fbconfig == None) {
00200     // If we didn't use an fbconfig to create the GSG, we can't create
00201     // a PBuffer.
00202     return false;
00203   }
00204 
00205   XVisualInfo *visual_info = eglgsg->_visual;
00206   if (visual_info == NULL) {
00207     // No X visual for this fbconfig; how can we create the pixmap?
00208     egldisplay_cat.error()
00209       << "No X visual: cannot create pixmap.\n";
00210     return false;
00211   }
00212 
00213   _drawable = egl_pipe->get_root();
00214   if (_host != NULL) {
00215     if (_host->is_of_type(eglGraphicsWindow::get_class_type())) {
00216       eglGraphicsWindow *win = DCAST(eglGraphicsWindow, _host);
00217       _drawable = win->get_xwindow();
00218     } else if (_host->is_of_type(eglGraphicsPixmap::get_class_type())) {
00219       eglGraphicsPixmap *pix = DCAST(eglGraphicsPixmap, _host);
00220       _drawable = pix->_drawable;
00221     }
00222   }
00223 
00224   _x_pixmap = XCreatePixmap(_display, _drawable, 
00225                             _x_size, _y_size, visual_info->depth);
00226   if (_x_pixmap == None) {
00227     egldisplay_cat.error()
00228       << "Failed to create X pixmap.\n";
00229     close_buffer();
00230     return false;
00231   }
00232 
00233   nassertr(eglgsg->_fbconfig, false);
00234   _egl_surface = eglCreatePixmapSurface(_egl_display, eglgsg->_fbconfig, (NativePixmapType) _x_pixmap, NULL);
00235 
00236   if (_egl_surface == EGL_NO_SURFACE) {
00237     egldisplay_cat.error()
00238       << "Failed to create EGL pixmap surface:"
00239       << get_egl_error_string(eglGetError()) << "\n";
00240     close_buffer();
00241     return false;
00242   }
00243 
00244   eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context);
00245   eglgsg->reset_if_new();
00246   if (!eglgsg->is_valid()) {
00247     close_buffer();
00248     return false;
00249   }
00250   if (!eglgsg->get_fb_properties().verify_hardware_software
00251       (_fb_properties, eglgsg->get_gl_renderer())) {
00252     close_buffer();
00253     return false;
00254   }
00255   _fb_properties = eglgsg->get_fb_properties();
00256   
00257   _is_valid = true;
00258   return true;
00259 }