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