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(_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, false, 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, false, true, false);
171  _gsg = eglgsg;
172  }
173  }
174 
175  if (eglgsg->_fbconfig == nullptr) {
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  _egl_display = eglgsg->_egl_display;
182 
183  int attrib_list[] = {
184  EGL_WIDTH, _size.get_x(),
185  EGL_HEIGHT, _size.get_y(),
186  EGL_NONE
187  };
188 
189  _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list);
190 
191  if (_pbuffer == EGL_NO_SURFACE) {
192  egldisplay_cat.error()
193  << "Failed to create EGL pbuffer surface: "
194  << get_egl_error_string(eglGetError()) << "\n";
195  return false;
196  }
197 
198  if (!eglMakeCurrent(eglgsg->_egl_display, _pbuffer, _pbuffer, eglgsg->_context)) {
199  egldisplay_cat.error() << "Failed to call eglMakeCurrent: "
200  << get_egl_error_string(eglGetError()) << "\n";
201  }
202  eglgsg->reset_if_new();
203  if (!eglgsg->is_valid()) {
204  close_buffer();
205  return false;
206  }
208  (_fb_properties, eglgsg->get_gl_renderer())) {
209  close_buffer();
210  return false;
211  }
212  _fb_properties = eglgsg->get_fb_properties();
213 
214  _is_valid = true;
215  return true;
216 }
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.
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.
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...
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.
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 graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
A tiny specialization on GLESGraphicsStateGuardian to add some egl-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, eglGraphicsPipe *egl_pipe, bool need_window, bool need_pbuffer, bool need_pixmap)
Selects a visual or fbconfig for all the windows and buffers that use this gsg.
const std::string get_egl_error_string(int error)
Returns the given EGL error as string.
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.