Panda3D
glxGraphicsWindow.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 glxGraphicsWindow.cxx
10  * @author mike
11  * @date 1997-01-09
12  */
13 
14 #include "glxGraphicsWindow.h"
16 #include "config_glxdisplay.h"
17 #include "glxGraphicsPipe.h"
18 
19 #include "graphicsPipe.h"
20 #include "keyboardButton.h"
21 #include "mouseButton.h"
22 #include "glgsg.h"
23 #include "clockObject.h"
24 #include "pStatTimer.h"
25 #include "textEncoder.h"
26 #include "throw_event.h"
27 #include "lightReMutexHolder.h"
28 
29 #include <errno.h>
30 #include <sys/time.h>
31 
32 TypeHandle glxGraphicsWindow::_type_handle;
33 
34 /**
35  *
36  */
37 glxGraphicsWindow::
38 glxGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
39  const std::string &name,
40  const FrameBufferProperties &fb_prop,
41  const WindowProperties &win_prop,
42  int flags,
44  GraphicsOutput *host) :
45  x11GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
46 {
47 }
48 
49 /**
50  * This function will be called within the draw thread before beginning
51  * rendering for a given frame. It should do whatever setup is required, and
52  * return true if the frame should be rendered, or false if it should be
53  * skipped.
54  */
56 begin_frame(FrameMode mode, Thread *current_thread) {
57  PStatTimer timer(_make_current_pcollector, current_thread);
58 
59  begin_frame_spam(mode);
60  if (_gsg == nullptr) {
61  return false;
62  }
63  if (_awaiting_configure) {
64  // Don't attempt to draw while we have just reconfigured the window and we
65  // haven't got the notification back yet.
66  return false;
67  }
68 
70  DCAST_INTO_R(glxgsg, _gsg, false);
71  {
72  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
73 
74  if (glXGetCurrentDisplay() == _display &&
75  glXGetCurrentDrawable() == _xwindow &&
76  glXGetCurrentContext() == glxgsg->_context) {
77  // No need to make the context current again. Short-circuit this
78  // possibly-expensive call.
79  } else {
80  // Need to set the context.
81  glXMakeCurrent(_display, _xwindow, glxgsg->_context);
82  }
83  }
84 
85  // Now that we have made the context current to a window, we can reset the
86  // GSG state if this is the first time it has been used. (We can't just
87  // call reset() when we construct the GSG, because reset() requires having a
88  // current context.)
89  glxgsg->reset_if_new();
90 
91  if (mode == FM_render) {
92  glxgsg->push_group_marker(std::string("glxGraphicsWindow ") + get_name());
93  // begin_render_texture();
94  clear_cube_map_selection();
95  }
96 
97  _gsg->set_current_properties(&get_fb_properties());
98  return _gsg->begin_frame(current_thread);
99 }
100 
101 
102 /**
103  * This function will be called within the draw thread after rendering is
104  * completed for a given frame. It should do whatever finalization is
105  * required.
106  */
108 end_frame(FrameMode mode, Thread *current_thread) {
109  end_frame_spam(mode);
110  nassertv(_gsg != nullptr);
111 
112  if (mode == FM_render) {
113  // end_render_texture();
114  copy_to_textures();
115  }
116 
117  _gsg->end_frame(current_thread);
118 
119  if (mode == FM_render) {
120  trigger_flip();
121  clear_cube_map_selection();
122 
123  glxGraphicsStateGuardian *glxgsg;
124  DCAST_INTO_V(glxgsg, _gsg);
125  glxgsg->pop_group_marker();
126  }
127 }
128 
129 /**
130  * This function will be called within the draw thread after begin_flip() has
131  * been called on all windows, to finish the exchange of the front and back
132  * buffers.
133  *
134  * This should cause the window to wait for the flip, if necessary.
135  */
138  if (_gsg != nullptr && _flip_ready) {
139 
140  // It doesn't appear to be necessary to ensure the graphics context is
141  // current before flipping the windows, and insisting on doing so can be a
142  // significant performance hit.
143 
144  // make_current();
145 
146  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
147  glXSwapBuffers(_display, _xwindow);
148  }
150 }
151 
152 /**
153  * Closes the window right now. Called from the window thread.
154  */
155 void glxGraphicsWindow::
156 close_window() {
157  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
158 
159  if (_gsg != nullptr) {
160  glXMakeCurrent(_display, None, nullptr);
161  _gsg.clear();
162  }
163 
164  x11GraphicsWindow::close_window();
165 }
166 
167 /**
168  * Opens the window right now. Called from the window thread. Returns true
169  * if the window is successfully opened, or false if there was a problem.
170  */
171 bool glxGraphicsWindow::
172 open_window() {
173  glxGraphicsPipe *glx_pipe;
174  DCAST_INTO_R(glx_pipe, _pipe, false);
175 
176  // GSG CreationInitialization
177  glxGraphicsStateGuardian *glxgsg;
178  if (_gsg == nullptr) {
179  // There is no old gsg. Create a new one.
180  glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, nullptr);
181  glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false);
182  _gsg = glxgsg;
183  } else {
184  // If the old gsg has the wrong pixel format, create a new one that shares
185  // with the old gsg.
186  DCAST_INTO_R(glxgsg, _gsg, false);
187  if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) {
188  glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
189  glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false);
190  _gsg = glxgsg;
191  }
192  }
193 
194  if (glxgsg->_context == nullptr) {
195  // We're supposed to have a context at this point.
196  glxdisplay_cat.error()
197  << "No GLX context: cannot open window.\n";
198  return false;
199  }
200 
201  _visual_info = glxgsg->_visual;
202  if (_visual_info == nullptr) {
203  // No X visual for this fbconfig; how can we open the window?
204  glxdisplay_cat.error()
205  << "No X visual: cannot open window.\n";
206  return false;
207  }
208 
209  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
210 
211  if (glxgsg->_fbconfig != None) {
212  setup_colormap(glxgsg->_fbconfig);
213  } else {
214  setup_colormap(_visual_info);
215  }
216 
217  if (!x11GraphicsWindow::open_window()) {
218  return false;
219  }
220 
221  glXMakeCurrent(_display, _xwindow, glxgsg->_context);
222  glxgsg->reset_if_new();
223  if (!glxgsg->is_valid()) {
224  close_window();
225  return false;
226  }
228  (_fb_properties, glxgsg->get_gl_renderer())) {
229  close_window();
230  return false;
231  }
232  _fb_properties = glxgsg->get_fb_properties();
233 
234  return true;
235 }
236 
237 /**
238  * Allocates a colormap appropriate to the fbconfig and stores in in the
239  * _colormap method.
240  */
241 void glxGraphicsWindow::
242 setup_colormap(GLXFBConfig fbconfig) {
243  glxGraphicsStateGuardian *glxgsg;
244  DCAST_INTO_V(glxgsg, _gsg);
245  nassertv(glxgsg->_supports_fbconfig);
246 
247  XVisualInfo *visual_info = glxgsg->_glXGetVisualFromFBConfig(_display, fbconfig);
248  if (visual_info == nullptr) {
249  // No X visual; no need to set up a colormap.
250  return;
251  }
252  int visual_class = visual_info->c_class;
253  Visual *visual = visual_info->visual;
254  XFree(visual_info);
255 
256  glxGraphicsPipe *glx_pipe;
257  DCAST_INTO_V(glx_pipe, _pipe);
258  X11_Window root_window = glx_pipe->get_root();
259 
260  int rc, is_rgb;
261 
262  switch (visual_class) {
263  case PseudoColor:
264  rc = glxgsg->_glXGetFBConfigAttrib(_display, fbconfig, GLX_RGBA, &is_rgb);
265  if (rc == 0 && is_rgb) {
266  glxdisplay_cat.warning()
267  << "mesa pseudocolor not supported.\n";
268  // this is a terrible terrible hack, but it seems to work
269  _colormap = (Colormap)0;
270 
271  } else {
272  _colormap = XCreateColormap(_display, root_window,
273  visual, AllocAll);
274  }
275  break;
276  case TrueColor:
277  case DirectColor:
278  _colormap = XCreateColormap(_display, root_window,
279  visual, AllocNone);
280  break;
281  case StaticColor:
282  case StaticGray:
283  case GrayScale:
284  _colormap = XCreateColormap(_display, root_window,
285  visual, AllocNone);
286  break;
287  default:
288  glxdisplay_cat.error()
289  << "Could not allocate a colormap for visual class "
290  << visual_class << ".\n";
291  break;
292  }
293 }
294 
295 /**
296  * Allocates a colormap appropriate to the visual and stores in in the
297  * _colormap method.
298  */
299 void glxGraphicsWindow::
300 setup_colormap(XVisualInfo *visual) {
301  glxGraphicsPipe *glx_pipe;
302  DCAST_INTO_V(glx_pipe, _pipe);
303  X11_Window root_window = glx_pipe->get_root();
304 
305  int visual_class = visual->c_class;
306  int rc, is_rgb;
307 
308  switch (visual_class) {
309  case PseudoColor:
310  rc = glXGetConfig(_display, visual, GLX_RGBA, &is_rgb);
311  if (rc == 0 && is_rgb) {
312  glxdisplay_cat.warning()
313  << "mesa pseudocolor not supported.\n";
314  // this is a terrible terrible hack, but it seems to work
315  _colormap = (Colormap)0;
316 
317  } else {
318  _colormap = XCreateColormap(_display, root_window,
319  visual->visual, AllocAll);
320  }
321  break;
322  case TrueColor:
323  case DirectColor:
324  _colormap = XCreateColormap(_display, root_window,
325  visual->visual, AllocNone);
326  break;
327  case StaticColor:
328  case StaticGray:
329  case GrayScale:
330  _colormap = XCreateColormap(_display, root_window,
331  visual->visual, AllocNone);
332  break;
333  default:
334  glxdisplay_cat.error()
335  << "Could not allocate a colormap for visual class "
336  << visual_class << ".\n";
337  break;
338  }
339 }
This graphics pipe represents the interface for creating OpenGL graphics windows on an X-based (e....
A tiny specialization on GLGraphicsStateGuardian to add some glx-specific information.
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...
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.
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
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.
X11_Window get_root() const
Returns the handle to the root window on the pipe's display.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
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.
int get_screen() const
Returns the X screen number associated with the pipe.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_name
Returns the name that was passed to the GraphicsOutput constructor.
A thread; that is, a lightweight process.
Definition: thread.h:46
Encapsulates all the communication with a particular instance of a given rendering backend.
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.
Interfaces to the X11 window system.
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.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.