Panda3D
glxGraphicsBuffer.cxx
1 // Filename: glxGraphicsBuffer.cxx
2 // Created by: drose (09Feb04)
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 "glxGraphicsBuffer.h"
16 #include "glxGraphicsStateGuardian.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 glxGraphicsBuffer::_type_handle;
25 
26 ////////////////////////////////////////////////////////////////////
27 // Function: glxGraphicsBuffer::Constructor
28 // Access: Public
29 // Description:
30 ////////////////////////////////////////////////////////////////////
31 glxGraphicsBuffer::
32 glxGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
33  const string &name,
34  const FrameBufferProperties &fb_prop,
35  const WindowProperties &win_prop,
36  int flags,
38  GraphicsOutput *host) :
39  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
40 {
41  glxGraphicsPipe *glx_pipe;
42  DCAST_INTO_V(glx_pipe, _pipe);
43  _display = glx_pipe->get_display();
44  _pbuffer = None;
45 
46  // Since the pbuffer never gets flipped, we get screenshots from the
47  // same buffer we draw into.
48  _screenshot_buffer_type = _draw_buffer_type;
49 }
50 
51 ////////////////////////////////////////////////////////////////////
52 // Function: glxGraphicsBuffer::Destructor
53 // Access: Public, Virtual
54 // Description:
55 ////////////////////////////////////////////////////////////////////
56 glxGraphicsBuffer::
57 ~glxGraphicsBuffer() {
58  nassertv(_pbuffer == None);
59 }
60 
61 ////////////////////////////////////////////////////////////////////
62 // Function: glxGraphicsBuffer::begin_frame
63 // Access: Public, Virtual
64 // Description: This function will be called within the draw thread
65 // before beginning rendering for a given frame. It
66 // should do whatever setup is required, and return true
67 // if the frame should be rendered, or false if it
68 // should be skipped.
69 ////////////////////////////////////////////////////////////////////
71 begin_frame(FrameMode mode, Thread *current_thread) {
72  PStatTimer timer(_make_current_pcollector, current_thread);
73 
74  begin_frame_spam(mode);
75  if (_gsg == (GraphicsStateGuardian *)NULL ||
76  _pbuffer == None) {
77  return false;
78  }
79 
81  DCAST_INTO_R(glxgsg, _gsg, false);
82  glXMakeCurrent(_display, _pbuffer, glxgsg->_context);
83 
84  // Now that we have made the context current to a window, we can
85  // reset the GSG state if this is the first time it has been used.
86  // (We can't just call reset() when we construct the GSG, because
87  // reset() requires having a current context.)
88  glxgsg->reset_if_new();
89 
90  if (mode == FM_render) {
91  CDLockedReader cdata(_cycler);
92  for (size_t i = 0; i != cdata->_textures.size(); ++i) {
93  const RenderTexture &rt = cdata->_textures[i];
94  RenderTextureMode rtm_mode = rt._rtm_mode;
95  if (rtm_mode == RTM_bind_or_copy) {
96  CDWriter cdataw(_cycler, cdata, false);
97  nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
98  cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
99  }
100  }
101  clear_cube_map_selection();
102  }
103 
104  _gsg->set_current_properties(&get_fb_properties());
105  return _gsg->begin_frame(current_thread);
106 }
107 
108 ////////////////////////////////////////////////////////////////////
109 // Function: glxGraphicsBuffer::end_frame
110 // Access: Public, Virtual
111 // Description: This function will be called within the draw thread
112 // after rendering is completed for a given frame. It
113 // should do whatever finalization is required.
114 ////////////////////////////////////////////////////////////////////
116 end_frame(FrameMode mode, Thread *current_thread) {
117  end_frame_spam(mode);
118  nassertv(_gsg != (GraphicsStateGuardian *)NULL);
119 
120  if (mode == FM_render) {
121  copy_to_textures();
122  }
123 
124  _gsg->end_frame(current_thread);
125 
126  if (mode == FM_render) {
127  trigger_flip();
128  clear_cube_map_selection();
129  }
130 }
131 
132 ////////////////////////////////////////////////////////////////////
133 // Function: glxGraphicsBuffer::close_buffer
134 // Access: Protected, Virtual
135 // Description: Closes the buffer right now. Called from the window
136 // thread.
137 ////////////////////////////////////////////////////////////////////
138 void glxGraphicsBuffer::
139 close_buffer() {
140  if (_gsg != (GraphicsStateGuardian *)NULL) {
141  glXMakeCurrent(_display, None, NULL);
142 
143  if (_pbuffer != None) {
144  glxGraphicsStateGuardian *glxgsg;
145  DCAST_INTO_V(glxgsg, _gsg);
146  glxgsg->_glXDestroyPbuffer(_display, _pbuffer);
147  _pbuffer = None;
148  }
149 
150  _gsg.clear();
151  }
152 
153  _pbuffer = None;
154  _is_valid = false;
155 }
156 
157 ////////////////////////////////////////////////////////////////////
158 // Function: glxGraphicsBuffer::open_buffer
159 // Access: Protected, Virtual
160 // Description: Opens the buffer right now. Called from the window
161 // thread. Returns true if the buffer is successfully
162 // opened, or false if there was a problem.
163 ////////////////////////////////////////////////////////////////////
164 bool glxGraphicsBuffer::
165 open_buffer() {
166  glxGraphicsPipe *glx_pipe;
167  DCAST_INTO_R(glx_pipe, _pipe, false);
168 
169  // GSG Creation/Initialization
170  glxGraphicsStateGuardian *glxgsg;
171  if (_gsg == 0) {
172  // There is no old gsg. Create a new one.
173  glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL);
174  glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true, false);
175  _gsg = glxgsg;
176  } else {
177  // If the old gsg has the wrong pixel format, create a
178  // new one that shares with the old gsg.
179  DCAST_INTO_R(glxgsg, _gsg, false);
180 
181  if (!glxgsg->_context_has_pbuffer ||
182  !glxgsg->get_fb_properties().subsumes(_fb_properties)) {
183  // We need a new pixel format, and hence a new GSG.
184  glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
185  glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), true, false);
186  _gsg = glxgsg;
187  }
188  }
189 
190  if (glxgsg->_fbconfig == None || !glxgsg->_context_has_pbuffer) {
191  // If we didn't use an fbconfig to create the GSG, or it doesn't
192  // support buffers, we can't create a PBuffer.
193  return false;
194  }
195 
196  nassertr(glxgsg->_supports_pbuffer, false);
197 
198  static const int max_attrib_list = 32;
199  int attrib_list[max_attrib_list];
200  int n = 0;
201 
202  if (glxgsg->_uses_sgix_pbuffer) {
203  // The SGI version passed in the size in the parameter list.
204  nassertr(n < max_attrib_list, false);
205  attrib_list[n] = (int)None;
206  _pbuffer = glxgsg->_glXCreateGLXPbufferSGIX(glxgsg->_display, glxgsg->_fbconfig,
207  get_x_size(), get_y_size(), attrib_list);
208  } else {
209  // The official GLX 1.3 version passes in the size in the attrib
210  // list.
211  attrib_list[n++] = GLX_PBUFFER_WIDTH;
212  attrib_list[n++] = get_x_size();
213  attrib_list[n++] = GLX_PBUFFER_HEIGHT;
214  attrib_list[n++] = get_y_size();
215 
216  nassertr(n < max_attrib_list, false);
217  attrib_list[n] = (int)None;
218  _pbuffer = glxgsg->_glXCreatePbuffer(glxgsg->_display, glxgsg->_fbconfig,
219  attrib_list);
220  }
221 
222  if (_pbuffer == None) {
223  glxdisplay_cat.error()
224  << "failed to create GLX pbuffer.\n";
225  return false;
226  }
227 
228  glXMakeCurrent(_display, _pbuffer, glxgsg->_context);
229  glxgsg->reset_if_new();
230  if (!glxgsg->is_valid()) {
231  close_buffer();
232  return false;
233  }
235  (_fb_properties, glxgsg->get_gl_renderer())) {
236  close_buffer();
237  return false;
238  }
239  _fb_properties = glxgsg->get_fb_properties();
240 
241  _is_valid = true;
242  return true;
243 }
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.
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.
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
A container for the various kinds of properties we might ask to have on a graphics window before we o...
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...
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...
This class is the main interface to controlling the render process.
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...
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...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.