Panda3D

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     for (int i=0; i<count_textures(); i++) {
00097       if (get_rtm_mode(i) == RTM_bind_or_copy) {
00098         _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: eglGraphicsPixmap::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 eglGraphicsPixmap::
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     if (_one_shot) {
00129       prepare_for_deletion();
00130     }
00131     clear_cube_map_selection();
00132   }
00133 }
00134 
00135 ////////////////////////////////////////////////////////////////////
00136 //     Function: eglGraphicsPixmap::close_buffer
00137 //       Access: Protected, Virtual
00138 //  Description: Closes the pixmap right now.  Called from the window
00139 //               thread.
00140 ////////////////////////////////////////////////////////////////////
00141 void eglGraphicsPixmap::
00142 close_buffer() {
00143   if (_gsg != (GraphicsStateGuardian *)NULL) {
00144     if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
00145       egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
00146         << get_egl_error_string(eglGetError()) << "\n";
00147     }
00148     _gsg.clear();
00149     _active = false;
00150   }
00151 
00152   if (_egl_surface != EGL_NO_SURFACE) {
00153     if (!eglDestroySurface(_egl_display, _egl_surface)) {
00154       egldisplay_cat.error() << "Failed to destroy surface: "
00155         << get_egl_error_string(eglGetError()) << "\n";
00156     }
00157     _egl_surface = EGL_NO_SURFACE;
00158   }
00159 
00160   if (_x_pixmap != None) {
00161     XFreePixmap(_display, _x_pixmap);
00162     _x_pixmap = None;
00163   }
00164 
00165   _is_valid = false;
00166 }
00167 
00168 ////////////////////////////////////////////////////////////////////
00169 //     Function: eglGraphicsPixmap::open_buffer
00170 //       Access: Protected, Virtual
00171 //  Description: Opens the pixmap right now.  Called from the window
00172 //               thread.  Returns true if the pixmap is successfully
00173 //               opened, or false if there was a problem.
00174 ////////////////////////////////////////////////////////////////////
00175 bool eglGraphicsPixmap::
00176 open_buffer() {
00177   eglGraphicsPipe *egl_pipe;
00178   DCAST_INTO_R(egl_pipe, _pipe, false);
00179 
00180   // GSG Creation/Initialization
00181   eglGraphicsStateGuardian *eglgsg;
00182   if (_gsg == 0) {
00183     // There is no old gsg.  Create a new one.
00184     eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL);
00185     eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true);
00186     _gsg = eglgsg;
00187   } else {
00188     // If the old gsg has the wrong pixel format, create a
00189     // new one that shares with the old gsg.
00190     DCAST_INTO_R(eglgsg, _gsg, false);
00191     if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
00192       eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
00193       eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true);
00194       _gsg = eglgsg;
00195     }
00196   }
00197   
00198   if (eglgsg->_fbconfig == None) {
00199     // If we didn't use an fbconfig to create the GSG, we can't create
00200     // a PBuffer.
00201     return false;
00202   }
00203 
00204   XVisualInfo *visual_info = eglgsg->_visual;
00205   if (visual_info == NULL) {
00206     // No X visual for this fbconfig; how can we create the pixmap?
00207     egldisplay_cat.error()
00208       << "No X visual: cannot create pixmap.\n";
00209     return false;
00210   }
00211 
00212   _drawable = egl_pipe->get_root();
00213   if (_host != NULL) {
00214     if (_host->is_of_type(eglGraphicsWindow::get_class_type())) {
00215       eglGraphicsWindow *win = DCAST(eglGraphicsWindow, _host);
00216       _drawable = win->get_xwindow();
00217     } else if (_host->is_of_type(eglGraphicsPixmap::get_class_type())) {
00218       eglGraphicsPixmap *pix = DCAST(eglGraphicsPixmap, _host);
00219       _drawable = pix->_drawable;
00220     }
00221   }
00222 
00223   _x_pixmap = XCreatePixmap(_display, _drawable, 
00224                             _x_size, _y_size, visual_info->depth);
00225   if (_x_pixmap == None) {
00226     egldisplay_cat.error()
00227       << "Failed to create X pixmap.\n";
00228     close_buffer();
00229     return false;
00230   }
00231 
00232   nassertr(eglgsg->_fbconfig, false);
00233   _egl_surface = eglCreatePixmapSurface(_egl_display, eglgsg->_fbconfig, (NativePixmapType) _x_pixmap, NULL);
00234 
00235   if (_egl_surface == EGL_NO_SURFACE) {
00236     egldisplay_cat.error()
00237       << "Failed to create EGL pixmap surface:"
00238       << get_egl_error_string(eglGetError()) << "\n";
00239     close_buffer();
00240     return false;
00241   }
00242 
00243   eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context);
00244   eglgsg->reset_if_new();
00245   if (!eglgsg->is_valid()) {
00246     close_buffer();
00247     return false;
00248   }
00249   if (!eglgsg->get_fb_properties().verify_hardware_software
00250       (_fb_properties, eglgsg->get_gl_renderer())) {
00251     close_buffer();
00252     return false;
00253   }
00254   _fb_properties = eglgsg->get_fb_properties();
00255   
00256   _is_valid = true;
00257   return true;
00258 }
 All Classes Functions Variables Enumerations