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