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