Panda3D
eglGraphicsBuffer.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 eglGraphicsBuffer.cxx
10  * @author rdb
11  * @date 2009-06-13
12  */
13 
14 #include "eglGraphicsBuffer.h"
16 #include "config_egldisplay.h"
17 #include "eglGraphicsPipe.h"
18 
19 #include "graphicsPipe.h"
20 #include "pStatTimer.h"
21 
22 TypeHandle eglGraphicsBuffer::_type_handle;
23 
24 /**
25  *
26  */
27 eglGraphicsBuffer::
28 eglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
29  const std::string &name,
30  const FrameBufferProperties &fb_prop,
31  const WindowProperties &win_prop,
32  int flags,
34  GraphicsOutput *host) :
35  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
36 {
37  eglGraphicsPipe *egl_pipe;
38  DCAST_INTO_V(egl_pipe, _pipe);
39  _pbuffer = EGL_NO_SURFACE;
40 
41  // Since the pbuffer never gets flipped, we get screenshots from the same
42  // buffer we draw into.
43  _screenshot_buffer_type = _draw_buffer_type;
44 }
45 
46 /**
47  *
48  */
49 eglGraphicsBuffer::
50 ~eglGraphicsBuffer() {
51  nassertv(_pbuffer == EGL_NO_SURFACE);
52 }
53 
54 /**
55  * This function will be called within the draw thread before beginning
56  * rendering for a given frame. It should do whatever setup is required, and
57  * return true if the frame should be rendered, or false if it should be
58  * skipped.
59  */
61 begin_frame(FrameMode mode, Thread *current_thread) {
62  PStatTimer timer(_make_current_pcollector, current_thread);
63 
64  begin_frame_spam(mode);
65  if (_gsg == nullptr) {
66  return false;
67  }
68 
70  DCAST_INTO_R(eglgsg, _gsg, false);
71  if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
72  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
73  << get_egl_error_string(eglGetError()) << "\n";
74  }
75 
76  // Now that we have made the context current to a window, we can reset the
77  // GSG state if this is the first time it has been used. (We can't just
78  // call reset() when we construct the GSG, because reset() requires having a
79  // current context.)
80  eglgsg->reset_if_new();
81 
82  if (mode == FM_render) {
83  CDLockedReader cdata(_cycler);
84  for (size_t i = 0; i != cdata->_textures.size(); ++i) {
85  const RenderTexture &rt = cdata->_textures[i];
86  RenderTextureMode rtm_mode = rt._rtm_mode;
87  if (rtm_mode == RTM_bind_or_copy) {
88  CDWriter cdataw(_cycler, cdata, false);
89  nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
90  cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
91  }
92  }
93  clear_cube_map_selection();
94  }
95 
96  _gsg->set_current_properties(&get_fb_properties());
97  return _gsg->begin_frame(current_thread);
98 }
99 
100 /**
101  * This function will be called within the draw thread after rendering is
102  * completed for a given frame. It should do whatever finalization is
103  * required.
104  */
106 end_frame(FrameMode mode, Thread *current_thread) {
107  end_frame_spam(mode);
108  nassertv(_gsg != nullptr);
109 
110  if (mode == FM_render) {
111  copy_to_textures();
112  }
113 
114  _gsg->end_frame(current_thread);
115 
116  if (mode == FM_render) {
117  trigger_flip();
118  clear_cube_map_selection();
119  }
120 }
121 
122 /**
123  * Closes the buffer right now. Called from the window thread.
124  */
125 void eglGraphicsBuffer::
126 close_buffer() {
127  if (_gsg != nullptr) {
128  eglGraphicsStateGuardian *eglgsg;
129  DCAST_INTO_V(eglgsg, _gsg);
130  if (!eglMakeCurrent(eglgsg->_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
131  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
132  << get_egl_error_string(eglGetError()) << "\n";
133  }
134  _gsg.clear();
135 
136  if (_pbuffer != EGL_NO_SURFACE) {
137  if (!eglDestroySurface(_egl_display, _pbuffer)) {
138  egldisplay_cat.error() << "Failed to destroy surface: "
139  << get_egl_error_string(eglGetError()) << "\n";
140  }
141  _pbuffer = EGL_NO_SURFACE;
142  }
143  }
144 
145  _is_valid = false;
146 }
147 
148 /**
149  * Opens the buffer right now. Called from the window thread. Returns true
150  * if the buffer is successfully opened, or false if there was a problem.
151  */
152 bool eglGraphicsBuffer::
153 open_buffer() {
154  eglGraphicsPipe *egl_pipe;
155  DCAST_INTO_R(egl_pipe, _pipe, false);
156 
157  // GSG CreationInitialization
158  eglGraphicsStateGuardian *eglgsg;
159  if (_gsg == 0) {
160  // There is no old gsg. Create a new one.
161  eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, nullptr);
162  eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false);
163  _gsg = eglgsg;
164  } else {
165  // If the old gsg has the wrong pixel format, create a new one that shares
166  // with the old gsg.
167  DCAST_INTO_R(eglgsg, _gsg, false);
168  if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) {
169  eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg);
170  eglgsg->choose_pixel_format(_fb_properties, egl_pipe->get_display(), egl_pipe->get_screen(), true, false);
171  _gsg = eglgsg;
172  }
173  }
174 
175  if (eglgsg->_fbconfig == None) {
176  // If we didn't use an fbconfig to create the GSG, we can't create a
177  // PBuffer.
178  return false;
179  }
180 
181  int attrib_list[] = {
182  EGL_WIDTH, _size.get_x(),
183  EGL_HEIGHT, _size.get_y(),
184  EGL_NONE
185  };
186 
187  _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list);
188 
189  if (_pbuffer == EGL_NO_SURFACE) {
190  egldisplay_cat.error()
191  << "Failed to create EGL pbuffer surface: "
192  << get_egl_error_string(eglGetError()) << "\n";
193  return false;
194  }
195 
196  if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
197  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
198  << get_egl_error_string(eglGetError()) << "\n";
199  }
200  eglgsg->reset_if_new();
201  if (!eglgsg->is_valid()) {
202  close_buffer();
203  return false;
204  }
206  (_fb_properties, eglgsg->get_gl_renderer())) {
207  close_buffer();
208  return false;
209  }
210  _fb_properties = eglgsg->get_fb_properties();
211 
212  _is_valid = true;
213  return true;
214 }
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.
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.
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
const FrameBufferProperties & get_fb_properties() const
Gets the FrameBufferProperties for all windows and buffers that use this GSG.
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.
int get_screen() const
Returns the X screen number associated with the pipe.
const std::string get_egl_error_string(int error)
Returns the given EGL error as string.
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).
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:46
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:81
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.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.