Panda3D
 All Classes Functions Variables Enumerations
eglGraphicsPixmap.cxx
1 // Filename: eglGraphicsPixmap.cxx
2 // Created by: rdb (13Jun09)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "eglGraphicsPixmap.h"
16 #include "eglGraphicsWindow.h"
17 #include "eglGraphicsStateGuardian.h"
18 #include "config_egldisplay.h"
19 #include "eglGraphicsPipe.h"
20 
21 #include "graphicsPipe.h"
22 #include "pStatTimer.h"
23 
24 TypeHandle eglGraphicsPixmap::_type_handle;
25 
26 ////////////////////////////////////////////////////////////////////
27 // Function: eglGraphicsPixmap::Constructor
28 // Access: Public
29 // Description:
30 ////////////////////////////////////////////////////////////////////
31 eglGraphicsPixmap::
32 eglGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe,
33  const string &name,
34  const FrameBufferProperties &fb_prop,
35  const WindowProperties &win_prop,
36  int flags,
38  GraphicsOutput *host) :
39  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
40 {
41  eglGraphicsPipe *egl_pipe;
42  DCAST_INTO_V(egl_pipe, _pipe);
43  _display = egl_pipe->get_display();
44  _egl_display = egl_pipe->_egl_display;
45  _drawable = None;
46  _x_pixmap = None;
47  _egl_surface = EGL_NO_SURFACE;
48 
49  // Since the pixmap never gets flipped, we get screenshots from the
50  // same pixmap we draw into.
51  _screenshot_buffer_type = _draw_buffer_type;
52 }
53 
54 ////////////////////////////////////////////////////////////////////
55 // Function: eglGraphicsPixmap::Destructor
56 // Access: Public, Virtual
57 // Description:
58 ////////////////////////////////////////////////////////////////////
59 eglGraphicsPixmap::
60 ~eglGraphicsPixmap() {
61  nassertv(_x_pixmap == None && _egl_surface == EGL_NO_SURFACE);
62 }
63 
64 ////////////////////////////////////////////////////////////////////
65 // Function: eglGraphicsPixmap::begin_frame
66 // Access: Public, Virtual
67 // Description: This function will be called within the draw thread
68 // before beginning rendering for a given frame. It
69 // should do whatever setup is required, and return true
70 // if the frame should be rendered, or false if it
71 // should be skipped.
72 ////////////////////////////////////////////////////////////////////
74 begin_frame(FrameMode mode, Thread *current_thread) {
75  PStatTimer timer(_make_current_pcollector, current_thread);
76 
77  begin_frame_spam(mode);
78  if (_gsg == (GraphicsStateGuardian *)NULL) {
79  return false;
80  }
81 
83  DCAST_INTO_R(eglgsg, _gsg, false);
84  if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context)) {
85  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
86  << get_egl_error_string(eglGetError()) << "\n";
87  }
88 
89  // Now that we have made the context current to a window, we can
90  // reset the GSG state if this is the first time it has been used.
91  // (We can't just call reset() when we construct the GSG, because
92  // reset() requires having a current context.)
93  eglgsg->reset_if_new();
94 
95  if (mode == FM_render) {
96  CDLockedReader cdata(_cycler);
97  for (size_t i = 0; i != cdata->_textures.size(); ++i) {
98  const RenderTexture &rt = cdata->_textures[i];
99  RenderTextureMode rtm_mode = rt._rtm_mode;
100  if (rtm_mode == RTM_bind_or_copy) {
101  CDWriter cdataw(_cycler, cdata, false);
102  nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
103  cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
104  }
105  }
106  clear_cube_map_selection();
107  }
108 
109  _gsg->set_current_properties(&get_fb_properties());
110  return _gsg->begin_frame(current_thread);
111 }
112 
113 ////////////////////////////////////////////////////////////////////
114 // Function: eglGraphicsPixmap::end_frame
115 // Access: Public, Virtual
116 // Description: This function will be called within the draw thread
117 // after rendering is completed for a given frame. It
118 // should do whatever finalization is required.
119 ////////////////////////////////////////////////////////////////////
121 end_frame(FrameMode mode, Thread *current_thread) {
122  end_frame_spam(mode);
123  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
124 
125  if (mode == FM_render) {
126  copy_to_textures();
127  }
128 
129  _gsg->end_frame(current_thread);
130 
131  if (mode == FM_render) {
132  trigger_flip();
133  clear_cube_map_selection();
134  }
135 }
136 
137 ////////////////////////////////////////////////////////////////////
138 // Function: eglGraphicsPixmap::close_buffer
139 // Access: Protected, Virtual
140 // Description: Closes the pixmap right now. Called from the window
141 // thread.
142 ////////////////////////////////////////////////////////////////////
143 void eglGraphicsPixmap::
144 close_buffer() {
145  if (_gsg != (GraphicsStateGuardian *)NULL) {
146  if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
147  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
148  << get_egl_error_string(eglGetError()) << "\n";
149  }
150  _gsg.clear();
151  }
152 
153  if (_egl_surface != EGL_NO_SURFACE) {
154  if (!eglDestroySurface(_egl_display, _egl_surface)) {
155  egldisplay_cat.error() << "Failed to destroy surface: "
156  << get_egl_error_string(eglGetError()) << "\n";
157  }
158  _egl_surface = EGL_NO_SURFACE;
159  }
160 
161  if (_x_pixmap != None) {
162  XFreePixmap(_display, _x_pixmap);
163  _x_pixmap = None;
164  }
165 
166  _is_valid = false;
167 }
168 
169 ////////////////////////////////////////////////////////////////////
170 // Function: eglGraphicsPixmap::open_buffer
171 // Access: Protected, Virtual
172 // Description: Opens the pixmap right now. Called from the window
173 // thread. Returns true if the pixmap is successfully
174 // opened, or false if there was a problem.
175 ////////////////////////////////////////////////////////////////////
176 bool eglGraphicsPixmap::
177 open_buffer() {
178  eglGraphicsPipe *egl_pipe;
179  DCAST_INTO_R(egl_pipe, _pipe, false);
180 
181  // GSG Creation/Initialization
182  eglGraphicsStateGuardian *eglgsg;
183  if (_gsg == 0) {
184  // There is no old gsg. Create a new one.
185  eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL);
186  eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true);
187  _gsg = eglgsg;
188  } else {
189  // If the old gsg has the wrong pixel format, create a
190  // new one that shares with the old gsg.
191  DCAST_INTO_R(eglgsg, _gsg, false);
192  if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
193  eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
194  eglgsg->choose_pixel_format(_fb_properties, _display, egl_pipe->get_screen(), false, true);
195  _gsg = eglgsg;
196  }
197  }
198 
199  if (eglgsg->_fbconfig == None) {
200  // If we didn't use an fbconfig to create the GSG, we can't create
201  // a PBuffer.
202  return false;
203  }
204 
205  XVisualInfo *visual_info = eglgsg->_visual;
206  if (visual_info == NULL) {
207  // No X visual for this fbconfig; how can we create the pixmap?
208  egldisplay_cat.error()
209  << "No X visual: cannot create pixmap.\n";
210  return false;
211  }
212 
213  _drawable = egl_pipe->get_root();
214  if (_host != NULL) {
215  if (_host->is_of_type(eglGraphicsWindow::get_class_type())) {
216  eglGraphicsWindow *win = DCAST(eglGraphicsWindow, _host);
217  _drawable = win->get_xwindow();
218  } else if (_host->is_of_type(eglGraphicsPixmap::get_class_type())) {
219  eglGraphicsPixmap *pix = DCAST(eglGraphicsPixmap, _host);
220  _drawable = pix->_drawable;
221  }
222  }
223 
224  _x_pixmap = XCreatePixmap(_display, _drawable,
225  _size.get_x(), _size.get_y(), visual_info->depth);
226  if (_x_pixmap == None) {
227  egldisplay_cat.error()
228  << "Failed to create X pixmap.\n";
229  close_buffer();
230  return false;
231  }
232 
233  nassertr(eglgsg->_fbconfig, false);
234  _egl_surface = eglCreatePixmapSurface(_egl_display, eglgsg->_fbconfig, (NativePixmapType) _x_pixmap, NULL);
235 
236  if (_egl_surface == EGL_NO_SURFACE) {
237  egldisplay_cat.error()
238  << "Failed to create EGL pixmap surface:"
239  << get_egl_error_string(eglGetError()) << "\n";
240  close_buffer();
241  return false;
242  }
243 
244  eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context);
245  eglgsg->reset_if_new();
246  if (!eglgsg->is_valid()) {
247  close_buffer();
248  return false;
249  }
251  (_fb_properties, eglgsg->get_gl_renderer())) {
252  close_buffer();
253  return false;
254  }
255  _fb_properties = eglgsg->get_fb_properties();
256 
257  _is_valid = true;
258  return true;
259 }
X11_Window get_root() const
Returns the handle to the root window on the pipe&#39;s display.
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame...
An interface to the egl system for managing GLES windows under X.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e...
bool verify_hardware_software(const FrameBufferProperties &props, const string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software)...
A container for the various kinds of properties we might ask to have on a graphics window before we o...
X11_Window get_xwindow() const
Returns the X11 Window handle.
An offscreen buffer for rendering into.
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame...
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:58
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
Another offscreen buffer in the EGL environment.
This is a base class for the various different classes that represent the result of a frame of render...
void choose_pixel_format(const FrameBufferProperties &properties, X11_Display *_display, int _screen, bool need_pbuffer, bool need_pixmap)
Selects a visual or fbconfig for all the windows and buffers that use this gsg.
A thread; that is, a lightweight process.
Definition: thread.h:51
int get_screen() const
Returns the X screen number associated with the pipe.
Encapsulates all the communication with a particular instance of a given rendering backend...
X11_Display * get_display() const
Returns a pointer to the X display associated with the pipe: the display on which to create the windo...
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
This class is the main interface to controlling the render process.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.