Panda3D
eglGraphicsPipe.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 eglGraphicsPipe.cxx
10  * @author rdb
11  * @date 2009-05-21
12  */
13 
14 #include "eglGraphicsBuffer.h"
15 #include "eglGraphicsPipe.h"
16 #include "eglGraphicsPixmap.h"
17 #include "eglGraphicsWindow.h"
19 #include "config_egldisplay.h"
20 #include "frameBufferProperties.h"
21 
22 #include <EGL/eglext.h>
23 
24 TypeHandle eglGraphicsPipe::_type_handle;
25 
26 /**
27  *
28  */
29 eglGraphicsPipe::
30 eglGraphicsPipe() {
31  // Check for client extensions.
32  vector_string extensions;
33  const char *ext_ptr = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
34  if (ext_ptr != nullptr) {
35  extract_words(ext_ptr, extensions);
36 
37  if (egldisplay_cat.is_debug()) {
38  std::ostream &out = egldisplay_cat.debug()
39  << "Supported EGL client extensions:\n";
40 
41  for (const std::string &extension : extensions) {
42  out << " " << extension << "\n";
43  }
44  }
45  }
46  else if (egldisplay_cat.is_debug()) {
47  eglGetError();
48  egldisplay_cat.debug()
49  << "EGL client extensions not supported.\n";
50  }
51 
52  EGLint major, minor;
53 
54  //NB. if the X11 display failed to open, _display will be 0, which is a valid
55  // input to eglGetDisplay - it means to open the default display.
56 #ifdef USE_X11
57  _egl_display = eglGetDisplay((NativeDisplayType) _display);
58 #else
59  _egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
60 #endif
61  if (_egl_display && !eglInitialize(_egl_display, &major, &minor)) {
62  egldisplay_cat.warning()
63  << "Couldn't initialize the default EGL display: "
64  << get_egl_error_string(eglGetError()) << "\n";
65  _egl_display = EGL_NO_DISPLAY;
66  }
67 
68  if (!_egl_display &&
69  std::find(extensions.begin(), extensions.end(), "EGL_EXT_platform_device") != extensions.end() &&
70  std::find(extensions.begin(), extensions.end(), "EGL_EXT_device_enumeration") != extensions.end()) {
71 
72  PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
73  (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
74 
75  EGLint num_devices = 0;
76  if (eglQueryDevicesEXT != nullptr &&
77  eglQueryDevicesEXT(0, nullptr, &num_devices) &&
78  num_devices > 0) {
79  EGLDeviceEXT *devices = (EGLDeviceEXT *)alloca(sizeof(EGLDeviceEXT) * num_devices);
80  eglQueryDevicesEXT(num_devices, devices, &num_devices);
81 
82  if (egldisplay_cat.is_debug()) {
83  egldisplay_cat.debug()
84  << "Found " << num_devices << " EGL devices.\n";
85  }
86 
87  PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
88  (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
89 
90  if (eglGetPlatformDisplayEXT != nullptr) {
91  for (EGLint i = 0; i < num_devices && !_egl_display; ++i) {
92  _egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devices[i], nullptr);
93 
94  if (_egl_display && !eglInitialize(_egl_display, &major, &minor)) {
95  egldisplay_cat.warning()
96  << "Couldn't initialize EGL platform display " << i << ": "
97  << get_egl_error_string(eglGetError()) << "\n";
98  _egl_display = EGL_NO_DISPLAY;
99  }
100  }
101  }
102  }
103  }
104 
105  if (!_egl_display) {
106  egldisplay_cat.error()
107  << "Failed to find or initialize a suitable EGL display connection.\n";
108  _is_valid = false;
109  return;
110  }
111 
112  if (egldisplay_cat.is_debug()) {
113  egldisplay_cat.debug()
114  << "Successfully initialized EGL display, got version " << major << "." << minor << "\n";
115  }
116 
117 #if defined(OPENGLES_1) || defined(OPENGLES_2)
118  if (!eglBindAPI(EGL_OPENGL_ES_API)) {
119  egldisplay_cat.error()
120  << "Couldn't bind EGL to the OpenGL ES API: "
121  << get_egl_error_string(eglGetError()) << "\n";
122 #else
123  if (!eglBindAPI(EGL_OPENGL_API)) {
124  egldisplay_cat.error()
125  << "Couldn't bind EGL to the OpenGL API: "
126  << get_egl_error_string(eglGetError()) << "\n";
127 #endif
128  _is_valid = false;
129  return;
130  }
131 
132  // Even if we don't have an X11 display, we can still render headless.
133  _is_valid = true;
134 }
135 
136 /**
137  *
138  */
139 eglGraphicsPipe::
140 ~eglGraphicsPipe() {
141  if (_egl_display) {
142  if (!eglTerminate(_egl_display)) {
143  egldisplay_cat.error() << "Failed to terminate EGL display: "
144  << get_egl_error_string(eglGetError()) << "\n";
145  }
146  }
147 }
148 
149 /**
150  * Returns the name of the rendering interface associated with this
151  * GraphicsPipe. This is used to present to the user to allow him/her to
152  * choose between several possible GraphicsPipes available on a particular
153  * platform, so the name should be meaningful and unique for a given platform.
154  */
155 std::string eglGraphicsPipe::
156 get_interface_name() const {
157 #if defined(OPENGLES_1) || defined(OPENGLES_2)
158  return "OpenGL ES";
159 #else
160  return "OpenGL";
161 #endif
162 }
163 
164 /**
165  * This function is passed to the GraphicsPipeSelection object to allow the
166  * user to make a default eglGraphicsPipe.
167  */
168 PT(GraphicsPipe) eglGraphicsPipe::
169 pipe_constructor() {
170  return new eglGraphicsPipe;
171 }
172 
173 /**
174  * Creates a new window on the pipe, if possible.
175  */
176 PT(GraphicsOutput) eglGraphicsPipe::
177 make_output(const std::string &name,
178  const FrameBufferProperties &fb_prop,
179  const WindowProperties &win_prop,
180  int flags,
181  GraphicsEngine *engine,
183  GraphicsOutput *host,
184  int retry,
185  bool &precertify) {
186 
187  if (!_is_valid) {
188  return nullptr;
189  }
190 
191  eglGraphicsStateGuardian *eglgsg = 0;
192  if (gsg != 0) {
193  DCAST_INTO_R(eglgsg, gsg, nullptr);
194  }
195 
196  bool support_rtt;
197  support_rtt = false;
198  /*
199  Currently, no support for eglGraphicsBuffer render-to-texture.
200  if (eglgsg) {
201  support_rtt =
202  eglgsg -> get_supports_render_texture() &&
203  support_render_texture;
204  }
205  */
206 
207  // First thing to try: an eglGraphicsWindow
208 
209  if (retry == 0) {
210 #ifdef USE_X11
211  if (!_display) {
212  return nullptr;
213  }
214  if (((flags&BF_require_parasite)!=0)||
215  ((flags&BF_refuse_window)!=0)||
216  ((flags&BF_resizeable)!=0)||
217  ((flags&BF_size_track_host)!=0)||
218  ((flags&BF_rtt_cumulative)!=0)||
219  ((flags&BF_can_bind_color)!=0)||
220  ((flags&BF_can_bind_every)!=0)) {
221  return nullptr;
222  }
223  return new eglGraphicsWindow(engine, this, name, fb_prop, win_prop,
224  flags, gsg, host);
225 #else
226  return nullptr;
227 #endif
228  }
229 
230  // Second thing to try: a GL(ES(2))GraphicsBuffer
231  if (retry == 1) {
232  if ((host==0)||
233  // (!gl_support_fbo)||
234  ((flags&BF_require_parasite)!=0)||
235  ((flags&BF_require_window)!=0)) {
236  return nullptr;
237  }
238  // Early failure - if we are sure that this buffer WONT meet specs, we can
239  // bail out early.
240  if ((flags & BF_fb_props_optional)==0) {
241  if (fb_prop.get_indexed_color() > 0 ||
242  fb_prop.get_back_buffers() > 0 ||
243  fb_prop.get_accum_bits() > 0) {
244  return nullptr;
245  }
246  }
247  // Early success - if we are sure that this buffer WILL meet specs, we can
248  // precertify it.
249  if ((eglgsg != 0) &&
250  (eglgsg->is_valid()) &&
251  (!eglgsg->needs_reset()) &&
252  (eglgsg->_supports_framebuffer_object) &&
253  (eglgsg->_glDrawBuffers != 0)&&
254  (fb_prop.is_basic())) {
255  precertify = true;
256  }
257 #ifdef OPENGLES_2
258  return new GLES2GraphicsBuffer(engine, this, name, fb_prop, win_prop,
259  flags, gsg, host);
260 #elif defined(OPENGLES_1)
261  return new GLESGraphicsBuffer(engine, this, name, fb_prop, win_prop,
262  flags, gsg, host);
263 #else
264  return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
265  flags, gsg, host);
266 #endif
267  }
268 
269  // Third thing to try: a eglGraphicsBuffer
270  if (retry == 2) {
271  if (((flags&BF_require_parasite)!=0)||
272  ((flags&BF_require_window)!=0)||
273  ((flags&BF_resizeable)!=0)||
274  ((flags&BF_size_track_host)!=0)) {
275  return nullptr;
276  }
277 
278  if (!support_rtt) {
279  if (((flags&BF_rtt_cumulative)!=0)||
280  ((flags&BF_can_bind_every)!=0)) {
281  // If we require Render-to-Texture, but can't be sure we support it,
282  // bail.
283  return nullptr;
284  }
285  }
286 
287  return new eglGraphicsBuffer(engine, this, name, fb_prop, win_prop,
288  flags, gsg, host);
289  }
290 
291  // Fourth thing to try: an eglGraphicsPixmap.
292  if (retry == 3) {
293 #ifdef USE_X11
294  if (!_display) {
295  return nullptr;
296  }
297  if (((flags&BF_require_parasite)!=0)||
298  ((flags&BF_require_window)!=0)||
299  ((flags&BF_resizeable)!=0)||
300  ((flags&BF_size_track_host)!=0)) {
301  return nullptr;
302  }
303 
304  if (((flags&BF_rtt_cumulative)!=0)||
305  ((flags&BF_can_bind_every)!=0)) {
306  return nullptr;
307  }
308 
309  return new eglGraphicsPixmap(engine, this, name, fb_prop, win_prop,
310  flags, gsg, host);
311 #else
312  return nullptr;
313 #endif
314  }
315 
316  // Nothing else left to try.
317  return nullptr;
318 }
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool is_basic() const
Returns true if the properties are extremely basic.
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...
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.
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...
An offscreen buffer in the EGL environment.
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
virtual std::string get_interface_name() const
Returns the name of the rendering interface associated with this GraphicsPipe.
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.