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