Panda3D
 All Classes Functions Variables Enumerations
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.
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
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.
X11_Window get_root() const
Returns the handle to the root window on the pipe&#39;s display.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
int get_screen() const
Returns the X screen number associated with the pipe.
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
bool verify_hardware_software(const FrameBufferProperties &props, const string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software)...
A container for the various kinds of properties we might ask to have on a graphics window before we o...
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:58
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
X11_Display * get_display() const
Returns a pointer to the X display associated with the pipe: the display on which to create the windo...
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...
This class is the main interface to controlling the render process.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
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...