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 }
glxGraphicsStateGuardian::get_fb_properties
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
Definition: glxGraphicsStateGuardian.I:19
FrameBufferProperties
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
Definition: frameBufferProperties.h:26
config_glxdisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
throw_event.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glgsg.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GraphicsOutput::get_name
get_name
Returns the name that was passed to the GraphicsOutput constructor.
Definition: graphicsOutput.h:120
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
mouseButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glxGraphicsPipe
This graphics pipe represents the interface for creating OpenGL graphics windows on an X-based (e....
Definition: glxGraphicsPipe.h:76
clockObject.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
x11GraphicsPipe::get_root
X11_Window get_root() const
Returns the handle to the root window on the pipe's display.
Definition: x11GraphicsPipe.I:35
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
glxGraphicsPipe.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glxGraphicsWindow::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: glxGraphicsWindow.cxx:137
glxGraphicsWindow::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: glxGraphicsWindow.cxx:108
GraphicsPipe
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
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
x11GraphicsPipe::get_screen
int get_screen() const
Returns the X screen number associated with the pipe.
Definition: x11GraphicsPipe.I:27
glxGraphicsStateGuardian::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: glxGraphicsStateGuardian.cxx:226
glxGraphicsWindow.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
textEncoder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glxGraphicsStateGuardian
A tiny specialization on GLGraphicsStateGuardian to add some glx-specific information.
Definition: glxGraphicsStateGuardian.h:74
lightReMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glxGraphicsStateGuardian.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glxGraphicsWindow::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: glxGraphicsWindow.cxx:56