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 template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
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).
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
An offscreen buffer for rendering into.
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
int get_y_size() const
Returns the visible height of the window or buffer, if it is known.
int get_x_size() const
Returns the visible width of the window or buffer, if it is known.
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
Encapsulates all the communication with a particular instance of a given rendering backend.
Similar to MutexHolder, but for a light reentrant mutex.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
A thread; that is, a lightweight process.
Definition: thread.h:46
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 window before we o...
This graphics pipe represents the interface for creating OpenGL graphics windows on an X-based (e....
Another offscreen buffer in the GLX environment.
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.
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.
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
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.
An interface to the glx system for managing GL windows under X.
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_Display * get_display() const
Returns a pointer to the X display associated with the pipe: the display on which to create the windo...
int get_screen() const
Returns the X screen number associated with the pipe.
static int disable_x_error_messages()
Globally disables the printing of error messages that are raised by the X11 system,...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.