Panda3D
glxGraphicsPixmap.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 glxGraphicsPixmap.cxx
10  * @author drose
11  * @date 2009-03-10
12  */
13 
14 #include "glxGraphicsPixmap.h"
15 #include "glxGraphicsWindow.h"
17 #include "config_glxdisplay.h"
18 #include "glxGraphicsPipe.h"
19 
20 #include "graphicsPipe.h"
21 #include "glgsg.h"
22 #include "pStatTimer.h"
23 
24 TypeHandle glxGraphicsPixmap::_type_handle;
25 
26 /**
27  *
28  */
29 glxGraphicsPixmap::
30 glxGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe,
31  const std::string &name,
32  const FrameBufferProperties &fb_prop,
33  const WindowProperties &win_prop,
34  int flags,
36  GraphicsOutput *host) :
37  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
38 {
39  glxGraphicsPipe *glx_pipe;
40  DCAST_INTO_V(glx_pipe, _pipe);
41  _display = glx_pipe->get_display();
42  _drawable = None;
43  _x_pixmap = None;
44  _glx_pixmap = None;
45 
46  // Since the pixmap never gets flipped, we get screenshots from the same
47  // pixmap we draw into.
48  _screenshot_buffer_type = _draw_buffer_type;
49 }
50 
51 /**
52  *
53  */
54 glxGraphicsPixmap::
55 ~glxGraphicsPixmap() {
56  nassertv(_x_pixmap == None && _glx_pixmap == None);
57 }
58 
59 /**
60  * This function will be called within the draw thread before beginning
61  * rendering for a given frame. It should do whatever setup is required, and
62  * return true if the frame should be rendered, or false if it should be
63  * skipped.
64  */
66 begin_frame(FrameMode mode, Thread *current_thread) {
67  PStatTimer timer(_make_current_pcollector, current_thread);
68 
69  begin_frame_spam(mode);
70  if (_gsg == nullptr ||
71  _glx_pixmap == None) {
72  return false;
73  }
74 
76  DCAST_INTO_R(glxgsg, _gsg, false);
77  {
78  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
79  glXMakeCurrent(_display, _glx_pixmap, glxgsg->_context);
80  }
81 
82  // Now that we have made the context current to a window, we can reset the
83  // GSG state if this is the first time it has been used. (We can't just
84  // call reset() when we construct the GSG, because reset() requires having a
85  // current context.)
86  glxgsg->reset_if_new();
87 
88  if (mode == FM_render) {
89  CDLockedReader cdata(_cycler);
90  for (size_t i = 0; i != cdata->_textures.size(); ++i) {
91  const RenderTexture &rt = cdata->_textures[i];
92  RenderTextureMode rtm_mode = rt._rtm_mode;
93  if (rtm_mode == RTM_bind_or_copy) {
94  CDWriter cdataw(_cycler, cdata, false);
95  nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
96  cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
97  }
98  }
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  * This function will be called within the draw thread after rendering is
108  * completed for a given frame. It should do whatever finalization is
109  * required.
110  */
112 end_frame(FrameMode mode, Thread *current_thread) {
113  end_frame_spam(mode);
114  nassertv(_gsg != nullptr);
115 
116  if (mode == FM_render) {
117  copy_to_textures();
118  }
119 
120  _gsg->end_frame(current_thread);
121 
122  if (mode == FM_render) {
123  trigger_flip();
124  clear_cube_map_selection();
125  }
126 }
127 
128 /**
129  * Closes the pixmap right now. Called from the window thread.
130  */
131 void glxGraphicsPixmap::
132 close_buffer() {
133  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
134  if (_gsg != nullptr) {
135  glXMakeCurrent(_display, None, nullptr);
136  _gsg.clear();
137  }
138 
139  if (_glx_pixmap != None) {
140  glXDestroyGLXPixmap(_display, _glx_pixmap);
141  _glx_pixmap = None;
142  }
143 
144  if (_x_pixmap != None) {
145  XFreePixmap(_display, _x_pixmap);
146  _x_pixmap = None;
147  }
148 
149  _is_valid = false;
150 }
151 
152 /**
153  * Opens the pixmap right now. Called from the window thread. Returns true
154  * if the pixmap is successfully opened, or false if there was a problem.
155  */
156 bool glxGraphicsPixmap::
157 open_buffer() {
158  glxGraphicsPipe *glx_pipe;
159  DCAST_INTO_R(glx_pipe, _pipe, false);
160 
161  // GSG CreationInitialization
162  glxGraphicsStateGuardian *glxgsg;
163  if (_gsg == nullptr) {
164  // There is no old gsg. Create a new one.
165  glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, nullptr);
166  glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
167  _gsg = glxgsg;
168  } else {
169  // If the old gsg has the wrong pixel format, create a new one that shares
170  // with the old gsg.
171  DCAST_INTO_R(glxgsg, _gsg, false);
172  if (!glxgsg->_context_has_pixmap ||
173  !glxgsg->get_fb_properties().subsumes(_fb_properties)) {
174  glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
175  glxgsg->choose_pixel_format(_fb_properties, _display, glx_pipe->get_screen(), false, true);
176  _gsg = glxgsg;
177  }
178  }
179 
180  if (!glxgsg->_context_has_pixmap) {
181  // Hmm, the GSG we created won't work.
182  return false;
183  }
184 
185  XVisualInfo *visual_info = glxgsg->_visual;
186  if (visual_info == nullptr) {
187  // No X visual for this fbconfig; how can we create the pixmap?
188  glxdisplay_cat.error()
189  << "No X visual: cannot create pixmap.\n";
190  return false;
191  }
192 
193  _drawable = glx_pipe->get_root();
194  if (_host != nullptr) {
195  if (_host->is_of_type(glxGraphicsWindow::get_class_type())) {
196  glxGraphicsWindow *win = DCAST(glxGraphicsWindow, _host);
197  _drawable = win->get_xwindow();
198  } else if (_host->is_of_type(glxGraphicsPixmap::get_class_type())) {
199  glxGraphicsPixmap *pix = DCAST(glxGraphicsPixmap, _host);
200  _drawable = pix->_drawable;
201  }
202  }
203 
204  LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
205  _x_pixmap = XCreatePixmap(_display, _drawable,
206  get_x_size(), get_y_size(), visual_info->depth);
207  if (_x_pixmap == None) {
208  glxdisplay_cat.error()
209  << "Failed to create X pixmap.\n";
210  close_buffer();
211  return false;
212  }
213 
214  if (glxgsg->_fbconfig) {
215  // Use the FBConfig to create the pixmap.
216  _glx_pixmap = glxgsg->_glXCreatePixmap(_display, glxgsg->_fbconfig, _x_pixmap, nullptr);
217  } else {
218  // Use the XVisual to create the pixmap.
219  _glx_pixmap = glXCreateGLXPixmap(_display, visual_info, _x_pixmap);
220  }
221 
222  if (_glx_pixmap == None) {
223  glxdisplay_cat.error()
224  << "Failed to create GLX pixmap.\n";
225  close_buffer();
226  return false;
227  }
228 
229  int error_count = x11GraphicsPipe::disable_x_error_messages();
230  glXMakeCurrent(_display, _glx_pixmap, glxgsg->_context);
231  if (x11GraphicsPipe::enable_x_error_messages() != error_count) {
232  // An error was generated during the glXMakeCurrent() call. Assume the
233  // worst.
234  close_buffer();
235  return false;
236  }
237 
238  glxgsg->reset_if_new();
239  if (!glxgsg->is_valid()) {
240  close_buffer();
241  return false;
242  }
244  (_fb_properties, glxgsg->get_gl_renderer())) {
245  close_buffer();
246  return false;
247  }
248  _fb_properties = glxgsg->get_fb_properties();
249 
250  _is_valid = true;
251  return true;
252 }
This graphics pipe represents the interface for creating OpenGL graphics windows on an X-based (e....
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.
A tiny specialization on GLGraphicsStateGuardian to add some glx-specific information.
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.
static int disable_x_error_messages()
Globally disables the printing of error messages that are raised by the X11 system,...
int get_y_size() const
Returns the visible height of the window or buffer, if it is known.
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.
static int enable_x_error_messages()
Reenables the printing of error messages after a previous call to disable_x_error_messages().
X11_Window get_xwindow() const
Returns the X11 Window handle.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
An offscreen buffer for rendering into.
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
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
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 template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
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.
int get_x_size() const
Returns the visible width of the window or buffer, if it is known.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
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.
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
An interface to the glx system for managing GL windows under X.
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.
Another offscreen buffer in the GLX environment.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.