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