Panda3D
eglGraphicsBuffer.cxx
1 // Filename: eglGraphicsBuffer.cxx
2 // Created by: rdb (13Jun09)
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 "eglGraphicsBuffer.h"
16 #include "eglGraphicsStateGuardian.h"
17 #include "config_egldisplay.h"
18 #include "eglGraphicsPipe.h"
19 
20 #include "graphicsPipe.h"
21 #include "pStatTimer.h"
22 
23 TypeHandle eglGraphicsBuffer::_type_handle;
24 
25 ////////////////////////////////////////////////////////////////////
26 // Function: eglGraphicsBuffer::Constructor
27 // Access: Public
28 // Description:
29 ////////////////////////////////////////////////////////////////////
30 eglGraphicsBuffer::
31 eglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
32  const string &name,
33  const FrameBufferProperties &fb_prop,
34  const WindowProperties &win_prop,
35  int flags,
37  GraphicsOutput *host) :
38  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
39 {
40  eglGraphicsPipe *egl_pipe;
41  DCAST_INTO_V(egl_pipe, _pipe);
42  _pbuffer = EGL_NO_SURFACE;
43 
44  // Since the pbuffer never gets flipped, we get screenshots from the
45  // same buffer we draw into.
46  _screenshot_buffer_type = _draw_buffer_type;
47 }
48 
49 ////////////////////////////////////////////////////////////////////
50 // Function: eglGraphicsBuffer::Destructor
51 // Access: Public, Virtual
52 // Description:
53 ////////////////////////////////////////////////////////////////////
54 eglGraphicsBuffer::
55 ~eglGraphicsBuffer() {
56  nassertv(_pbuffer == EGL_NO_SURFACE);
57 }
58 
59 ////////////////////////////////////////////////////////////////////
60 // Function: eglGraphicsBuffer::begin_frame
61 // Access: Public, Virtual
62 // Description: This function will be called within the draw thread
63 // before beginning rendering for a given frame. It
64 // should do whatever setup is required, and return true
65 // if the frame should be rendered, or false if it
66 // should be skipped.
67 ////////////////////////////////////////////////////////////////////
69 begin_frame(FrameMode mode, Thread *current_thread) {
70  PStatTimer timer(_make_current_pcollector, current_thread);
71 
72  begin_frame_spam(mode);
73  if (_gsg == (GraphicsStateGuardian *)NULL) {
74  return false;
75  }
76 
78  DCAST_INTO_R(eglgsg, _gsg, false);
79  if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
80  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
81  << get_egl_error_string(eglGetError()) << "\n";
82  }
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  eglgsg->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: eglGraphicsBuffer::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: eglGraphicsBuffer::close_buffer
134 // Access: Protected, Virtual
135 // Description: Closes the buffer right now. Called from the window
136 // thread.
137 ////////////////////////////////////////////////////////////////////
138 void eglGraphicsBuffer::
139 close_buffer() {
140  if (_gsg != (GraphicsStateGuardian *)NULL) {
141  eglGraphicsStateGuardian *eglgsg;
142  DCAST_INTO_V(eglgsg, _gsg);
143  if (!eglMakeCurrent(eglgsg->_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
144  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
145  << get_egl_error_string(eglGetError()) << "\n";
146  }
147  _gsg.clear();
148 
149  if (_pbuffer != EGL_NO_SURFACE) {
150  if (!eglDestroySurface(_egl_display, _pbuffer)) {
151  egldisplay_cat.error() << "Failed to destroy surface: "
152  << get_egl_error_string(eglGetError()) << "\n";
153  }
154  _pbuffer = EGL_NO_SURFACE;
155  }
156  }
157 
158  _is_valid = false;
159 }
160 
161 ////////////////////////////////////////////////////////////////////
162 // Function: eglGraphicsBuffer::open_buffer
163 // Access: Protected, Virtual
164 // Description: Opens the buffer right now. Called from the window
165 // thread. Returns true if the buffer is successfully
166 // opened, or false if there was a problem.
167 ////////////////////////////////////////////////////////////////////
168 bool eglGraphicsBuffer::
169 open_buffer() {
170  eglGraphicsPipe *egl_pipe;
171  DCAST_INTO_R(egl_pipe, _pipe, false);
172 
173  // GSG Creation/Initialization
174  eglGraphicsStateGuardian *eglgsg;
175  if (_gsg == 0) {
176  // There is no old gsg. Create a new one.
177  eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, NULL);
178  eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false);
179  _gsg = eglgsg;
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(eglgsg, _gsg, false);
184  if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
185  eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
186  eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false);
187  _gsg = eglgsg;
188  }
189  }
190 
191  if (eglgsg->_fbconfig == None) {
192  // If we didn't use an fbconfig to create the GSG, we can't create
193  // a PBuffer.
194  return false;
195  }
196 
197  int attrib_list[] = {
198  EGL_WIDTH, _size.get_x(),
199  EGL_HEIGHT, _size.get_y(),
200  EGL_NONE
201  };
202 
203  _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list);
204 
205  if (_pbuffer == EGL_NO_SURFACE) {
206  egldisplay_cat.error()
207  << "Failed to create EGL pbuffer surface: "
208  << get_egl_error_string(eglGetError()) << "\n";
209  return false;
210  }
211 
212  if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
213  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
214  << get_egl_error_string(eglGetError()) << "\n";
215  }
216  eglgsg->reset_if_new();
217  if (!eglgsg->is_valid()) {
218  close_buffer();
219  return false;
220  }
222  (_fb_properties, eglgsg->get_gl_renderer())) {
223  close_buffer();
224  return false;
225  }
226  _fb_properties = eglgsg->get_fb_properties();
227 
228  _is_valid = true;
229  return true;
230 }
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e...
int get_screen() const
Returns the X screen number associated with the pipe.
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
X11_Display * get_display() const
Returns a pointer to the X display associated with the pipe: the display on which to create the windo...
A container for the various kinds of properties we might ask to have on a graphics window before we o...
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...
An offscreen buffer for rendering into.
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)...
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...
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.
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...
A thread; that is, a lightweight process.
Definition: thread.h:51
Encapsulates all the communication with a particular instance of a given rendering backend...
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
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.
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.