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