Panda3D
eglGraphicsWindow.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 eglGraphicsWindow.cxx
10  * @author rdb
11  * @date 2009-05-21
12  */
13 
14 #include "eglGraphicsWindow.h"
16 #include "config_egldisplay.h"
17 #include "eglGraphicsPipe.h"
18 
19 #include "graphicsPipe.h"
20 #include "keyboardButton.h"
21 #include "mouseButton.h"
22 #include "clockObject.h"
23 #include "pStatTimer.h"
24 #include "textEncoder.h"
25 #include "throw_event.h"
26 #include "lightReMutexHolder.h"
27 #include "nativeWindowHandle.h"
28 #include "get_x11.h"
29 
30 TypeHandle eglGraphicsWindow::_type_handle;
31 
32 /**
33  *
34  */
35 eglGraphicsWindow::
36 eglGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
37  const std::string &name,
38  const FrameBufferProperties &fb_prop,
39  const WindowProperties &win_prop,
40  int flags,
42  GraphicsOutput *host) :
43  x11GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
44 {
45  eglGraphicsPipe *egl_pipe;
46  DCAST_INTO_V(egl_pipe, _pipe);
47  _egl_display = egl_pipe->_egl_display;
48  _egl_surface = 0;
49 }
50 
51 /**
52  *
53  */
54 eglGraphicsWindow::
55 ~eglGraphicsWindow() {
56 }
57 
58 /**
59  * This function will be called within the draw thread before beginning
60  * rendering for a given frame. It should do whatever setup is required, and
61  * return true if the frame should be rendered, or false if it should be
62  * skipped.
63  */
65 begin_frame(FrameMode mode, Thread *current_thread) {
66  PStatTimer timer(_make_current_pcollector, current_thread);
67 
68  begin_frame_spam(mode);
69  if (_gsg == nullptr) {
70  return false;
71  }
72  if (_awaiting_configure) {
73  // Don't attempt to draw while we have just reconfigured the window and we
74  // haven't got the notification back yet.
75  return false;
76  }
77 
79  DCAST_INTO_R(eglgsg, _gsg, false);
80  {
81  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
82 
83  if (eglGetCurrentDisplay() == _egl_display &&
84  eglGetCurrentSurface(EGL_READ) == _egl_surface &&
85  eglGetCurrentSurface(EGL_DRAW) == _egl_surface &&
86  eglGetCurrentContext() == eglgsg->_context) {
87  // No need to make the context current again. Short-circuit this
88  // possibly-expensive call.
89  } else {
90  // Need to set the context.
91  if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context)) {
92  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
93  << get_egl_error_string(eglGetError()) << "\n";
94  }
95  }
96  }
97 
98  // Now that we have made the context current to a window, we can reset the
99  // GSG state if this is the first time it has been used. (We can't just
100  // call reset() when we construct the GSG, because reset() requires having a
101  // current context.)
102  eglgsg->reset_if_new();
103 
104  if (mode == FM_render) {
105  // begin_render_texture();
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  * This function will be called within the draw thread after rendering is
115  * completed for a given frame. It should do whatever finalization is
116  * required.
117  */
119 end_frame(FrameMode mode, Thread *current_thread) {
120  end_frame_spam(mode);
121  nassertv(_gsg != nullptr);
122 
123  if (mode == FM_render) {
124  // end_render_texture();
125  copy_to_textures();
126  }
127 
128  _gsg->end_frame(current_thread);
129 
130  if (mode == FM_render) {
131  trigger_flip();
132  clear_cube_map_selection();
133  }
134 }
135 
136 /**
137  * This function will be called within the draw thread after begin_flip() has
138  * been called on all windows, to finish the exchange of the front and back
139  * buffers.
140  *
141  * This should cause the window to wait for the flip, if necessary.
142  */
145  if (_gsg != nullptr && _flip_ready) {
146 
147  // It doesn't appear to be necessary to ensure the graphics context is
148  // current before flipping the windows, and insisting on doing so can be a
149  // significant performance hit.
150 
151  // make_current();
152 
153  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
154  eglSwapBuffers(_egl_display, _egl_surface);
155  }
157 }
158 
159 /**
160  * Closes the window right now. Called from the window thread.
161  */
162 void eglGraphicsWindow::
163 close_window() {
164  if (_gsg != nullptr) {
165  if (!eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
166  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
167  << get_egl_error_string(eglGetError()) << "\n";
168  }
169  _gsg.clear();
170  }
171 
172  if (_ic != (XIC)nullptr) {
173  XDestroyIC(_ic);
174  _ic = (XIC)nullptr;
175  }
176 
177  if (_egl_surface != 0) {
178  if (!eglDestroySurface(_egl_display, _egl_surface)) {
179  egldisplay_cat.error() << "Failed to destroy surface: "
180  << get_egl_error_string(eglGetError()) << "\n";
181  }
182  }
183 
184  if (_xwindow != (X11_Window)nullptr) {
185  XDestroyWindow(_display, _xwindow);
186  _xwindow = (X11_Window)nullptr;
187 
188  // This may be necessary if we just closed the last X window in an
189  // application, so the server hears the close request.
190  XFlush(_display);
191  }
192  GraphicsWindow::close_window();
193 }
194 
195 /**
196  * Opens the window right now. Called from the window thread. Returns true
197  * if the window is successfully opened, or false if there was a problem.
198  */
199 bool eglGraphicsWindow::
200 open_window() {
201  eglGraphicsPipe *egl_pipe;
202  DCAST_INTO_R(egl_pipe, _pipe, false);
203 
204  // GSG CreationInitialization
205  eglGraphicsStateGuardian *eglgsg;
206  if (_gsg == 0) {
207  // There is no old gsg. Create a new one.
208  eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, nullptr);
209  eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), false, false);
210  _gsg = eglgsg;
211  } else {
212  // If the old gsg has the wrong pixel format, create a new one that shares
213  // with the old gsg.
214  DCAST_INTO_R(eglgsg, _gsg, false);
215  if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
216  eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
217  eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), false, false);
218  _gsg = eglgsg;
219  }
220  }
221 
222  _visual_info = eglgsg->_visual;
223  if (_visual_info == nullptr) {
224  // No X visual for this fbconfig; how can we open the window?
225  egldisplay_cat.error()
226  << "No X visual: cannot open window.\n";
227  return false;
228  }
229 
230  setup_colormap(_visual_info);
231 
232  if (!x11GraphicsWindow::open_window()) {
233  return false;
234  }
235 
236  _egl_surface = eglCreateWindowSurface(_egl_display, eglgsg->_fbconfig, (NativeWindowType) _xwindow, nullptr);
237  if (eglGetError() != EGL_SUCCESS) {
238  egldisplay_cat.error()
239  << "Failed to create window surface.\n";
240  return false;
241  }
242 
243  if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, eglgsg->_context)) {
244  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
245  << get_egl_error_string(eglGetError()) << "\n";
246  }
247  eglgsg->reset_if_new();
248  if (!eglgsg->is_valid()) {
249  close_window();
250  return false;
251  }
253  (_fb_properties, eglgsg->get_gl_renderer())) {
254  close_window();
255  return false;
256  }
257  _fb_properties = eglgsg->get_fb_properties();
258 
259  return true;
260 }
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.
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
int get_screen() const
Returns the X screen number associated with the pipe.
const std::string get_egl_error_string(int error)
Returns the given EGL error as string.
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
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 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).
Similar to MutexHolder, but for a light reentrant mutex.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
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...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Interfaces to the X11 window system.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.