Panda3D
eglGraphicsStateGuardian.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 eglGraphicsStateGuardian.cxx
10  * @author rdb
11  * @date 2009-05-21
12  */
13 
15 #include "config_egldisplay.h"
16 #include "lightReMutexHolder.h"
17 
18 #include <dlfcn.h>
19 
20 TypeHandle eglGraphicsStateGuardian::_type_handle;
21 
22 /**
23  *
24  */
25 eglGraphicsStateGuardian::
26 eglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
27  eglGraphicsStateGuardian *share_with) :
28 #ifdef OPENGLES_2
29  GLES2GraphicsStateGuardian(engine, pipe)
30 #else
31  GLESGraphicsStateGuardian(engine, pipe)
32 #endif
33 {
34  _share_context=0;
35  _context=0;
36  _display=0;
37  _egl_display=0;
38  _screen=0;
39  _visual=0;
40  _visuals=0;
41  _fbconfig=0;
42 
43  if (share_with != nullptr) {
44  _prepared_objects = share_with->get_prepared_objects();
45  _share_context = share_with->_context;
46  }
47 }
48 
49 /**
50  *
51  */
52 eglGraphicsStateGuardian::
53 ~eglGraphicsStateGuardian() {
54  if (_visuals != nullptr) {
55  XFree(_visuals);
56  }
57  if (_context != (EGLContext)nullptr) {
58  if (!eglDestroyContext(_egl_display, _context)) {
59  egldisplay_cat.error() << "Failed to destroy EGL context: "
60  << get_egl_error_string(eglGetError()) << "\n";
61  }
62  _context = (EGLContext)nullptr;
63  }
64 }
65 
66 /**
67  * Gets the FrameBufferProperties to match the indicated config.
68  */
71  bool &pbuffer_supported, bool &pixmap_supported,
72  bool &slow, EGLConfig config) {
73 
74  properties.clear();
75 
76  // Now update our framebuffer_mode and bit depth appropriately.
77  EGLint red_size, green_size, blue_size,
78  alpha_size,
79  depth_size, stencil_size, samples, surface_type, caveat;
80 
81  eglGetConfigAttrib(_egl_display, config, EGL_RED_SIZE, &red_size);
82  eglGetConfigAttrib(_egl_display, config, EGL_GREEN_SIZE, &green_size);
83  eglGetConfigAttrib(_egl_display, config, EGL_BLUE_SIZE, &blue_size);
84  eglGetConfigAttrib(_egl_display, config, EGL_ALPHA_SIZE, &alpha_size);
85  eglGetConfigAttrib(_egl_display, config, EGL_DEPTH_SIZE, &depth_size);
86  eglGetConfigAttrib(_egl_display, config, EGL_STENCIL_SIZE, &stencil_size);
87  eglGetConfigAttrib(_egl_display, config, EGL_SAMPLES, &samples);
88  eglGetConfigAttrib(_egl_display, config, EGL_SURFACE_TYPE, &surface_type);
89  eglGetConfigAttrib(_egl_display, config, EGL_CONFIG_CAVEAT, &caveat);
90  int err = eglGetError();
91  if (err != EGL_SUCCESS) {
92  egldisplay_cat.error() << "Failed to get EGL config attrib: "
93  << get_egl_error_string(err) << "\n";
94  }
95 
96  pbuffer_supported = false;
97  if ((surface_type & EGL_PBUFFER_BIT)!=0) {
98  pbuffer_supported = true;
99  }
100 
101  pixmap_supported = false;
102  if ((surface_type & EGL_PIXMAP_BIT)!=0) {
103  pixmap_supported = true;
104  }
105 
106  slow = false;
107  if (caveat == EGL_SLOW_CONFIG) {
108  slow = true;
109  }
110 
111  if ((surface_type & EGL_WINDOW_BIT)==0) {
112  // We insist on having a context that will support an onscreen window.
113  return;
114  }
115 
116  properties.set_back_buffers(1);
117  properties.set_rgb_color(1);
118  properties.set_rgba_bits(red_size, green_size, blue_size, alpha_size);
119  properties.set_stencil_bits(stencil_size);
120  properties.set_depth_bits(depth_size);
121  properties.set_multisamples(samples);
122 
123  // Set both hardware and software bits, indicating not-yet-known.
124  properties.set_force_software(1);
125  properties.set_force_hardware(1);
126 }
127 
128 /**
129  * Selects a visual or fbconfig for all the windows and buffers that use this
130  * gsg. Also creates the GL context and obtains the visual.
131  */
134  X11_Display *display,
135  int screen, bool need_pbuffer, bool need_pixmap) {
136 
137  _display = display;
138  _egl_display = eglGetDisplay((NativeDisplayType) display);
139  _screen = screen;
140  _context = 0;
141  _fbconfig = 0;
142  _visual = 0;
143  _visuals = 0;
144  _fbprops.clear();
145 
146  int attrib_list[] = {
147 #ifdef OPENGLES_1
148  EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
149 #endif
150 #ifdef OPENGLES_2
151  EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
152 #endif
153  EGL_SURFACE_TYPE, EGL_DONT_CARE,
154  EGL_NONE
155  };
156 
157  // First get the number of matching configurations, so we know how much
158  // memory to allocate.
159  int num_configs = 0, returned_configs;
160  if (!eglChooseConfig(_egl_display, attrib_list, nullptr, num_configs, &returned_configs) || returned_configs <= 0) {
161  egldisplay_cat.error() << "eglChooseConfig failed: "
162  << get_egl_error_string(eglGetError()) << "\n";
163  return;
164  }
165 
166  num_configs = returned_configs;
167  EGLConfig *configs = new EGLConfig[num_configs];
168 
169  if (!eglChooseConfig(_egl_display, attrib_list, configs, num_configs, &returned_configs) || returned_configs <= 0) {
170  egldisplay_cat.error() << "eglChooseConfig failed: "
171  << get_egl_error_string(eglGetError()) << "\n";
172  delete[] configs;
173  return;
174  }
175 
176  int best_quality = 0;
177  int best_result = 0;
178  FrameBufferProperties best_props;
179 
180  for (int i = 0; i < num_configs; ++i) {
181  FrameBufferProperties fbprops;
182  bool pbuffer_supported, pixmap_supported, slow;
183  get_properties(fbprops, pbuffer_supported, pixmap_supported,
184  slow, configs[i]);
185  // We're not protecting this code by an is_debug() check, because if we
186  // do, some weird compiler bug appears and somehow makes the quality
187  // always 0.
188  const char *pbuffertext = pbuffer_supported ? " (pbuffer)" : "";
189  const char *pixmaptext = pixmap_supported ? " (pixmap)" : "";
190  const char *slowtext = slow ? " (slow)" : "";
191  egldisplay_cat.debug()
192  << i << ": " << fbprops << pbuffertext << pixmaptext << slowtext << "\n";
193  int quality = fbprops.get_quality(properties);
194  if ((quality > 0)&&(slow)) quality -= 10000000;
195 
196  if (need_pbuffer && !pbuffer_supported) {
197  continue;
198  }
199  if (need_pixmap && !pixmap_supported) {
200  continue;
201  }
202 
203  if (quality > best_quality) {
204  best_quality = quality;
205  best_result = i;
206  best_props = fbprops;
207  }
208  }
209  int depth = DefaultDepth(_display, _screen);
210  _visual = new XVisualInfo;
211  XMatchVisualInfo(_display, _screen, depth, TrueColor, _visual);
212 
213  if (best_quality > 0) {
214  egldisplay_cat.debug()
215  << "Chosen config " << best_result << ": " << best_props << "\n";
216  _fbconfig = configs[best_result];
217 #ifdef OPENGLES_2
218  EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
219  _context = eglCreateContext(_egl_display, _fbconfig, _share_context, context_attribs);
220 #else
221  _context = eglCreateContext(_egl_display, _fbconfig, _share_context, nullptr);
222 #endif
223  int err = eglGetError();
224  if (_context && err == EGL_SUCCESS) {
225  if (_visual) {
226  _fbprops = best_props;
227  delete[] configs;
228  return;
229  }
230  }
231  // This really shouldn't happen, so I'm not too careful about cleanup.
232  egldisplay_cat.error()
233  << "Could not create EGL context!\n"
234  << get_egl_error_string(err) << "\n";
235  _fbconfig = 0;
236  _context = 0;
237  _visual = 0;
238  _visuals = 0;
239  }
240 
241  egldisplay_cat.error() <<
242  "Could not find a usable pixel format.\n";
243 
244  delete[] configs;
245 }
246 
247 /**
248  * Resets all internal state as if the gsg were newly created.
249  */
251 reset() {
252 #ifdef OPENGLES_2
253  GLES2GraphicsStateGuardian::reset();
254 #else
255  GLESGraphicsStateGuardian::reset();
256 #endif
257 
258  // If "Mesa" is present, assume software. However, if "Mesa DRI" is found,
259  // it's actually a Mesa-based OpenGL layer running over a hardware driver.
260  if (_gl_renderer == "Software Rasterizer" ||
261  (_gl_renderer.find("Mesa") != std::string::npos &&
262  _gl_renderer.find("Mesa DRI") == std::string::npos)) {
263  // It's Mesa, therefore probably a software context.
264  _fbprops.set_force_software(1);
265  _fbprops.set_force_hardware(0);
266  } else {
267  _fbprops.set_force_hardware(1);
268  _fbprops.set_force_software(0);
269  }
270 }
271 
272 /**
273  * Returns true if the runtime GLX version number is at least the indicated
274  * value, false otherwise.
275  */
277 egl_is_at_least_version(int major_version, int minor_version) const {
278  if (_egl_version_major < major_version) {
279  return false;
280  }
281  if (_egl_version_minor < minor_version) {
282  return false;
283  }
284  return true;
285 }
286 
287 /**
288  * Calls glFlush().
289  */
290 void eglGraphicsStateGuardian::
291 gl_flush() const {
292  // This call requires synchronization with X.
293  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
294 #ifdef OPENGLES_2
295  GLES2GraphicsStateGuardian::gl_flush();
296 #else
297  GLESGraphicsStateGuardian::gl_flush();
298 #endif
299 }
300 
301 /**
302  * Returns the result of glGetError().
303  */
304 GLenum eglGraphicsStateGuardian::
305 gl_get_error() const {
306  // This call requires synchronization with X.
307  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
308 #ifdef OPENGLES_2
309  return GLES2GraphicsStateGuardian::gl_get_error();
310 #else
311  return GLESGraphicsStateGuardian::gl_get_error();
312 #endif
313 }
314 
315 /**
316  * Queries the runtime version of OpenGL in use.
317  */
318 void eglGraphicsStateGuardian::
319 query_gl_version() {
320 #ifdef OPENGLES_2
321  GLES2GraphicsStateGuardian::query_gl_version();
322 #else
323  GLESGraphicsStateGuardian::query_gl_version();
324 #endif
325 
326  // Calling eglInitialize on an already-initialized display will just provide
327  // us the version numbers.
328  if (!eglInitialize(_egl_display, &_egl_version_major, &_egl_version_minor)) {
329  egldisplay_cat.error() << "Failed to get EGL version number: "
330  << get_egl_error_string(eglGetError()) << "\n";
331  }
332 
333  // We output to glesgsg_cat instead of egldisplay_cat, since this is where
334  // the GL version has been output, and it's nice to see the two of these
335  // together.
336 #ifdef OPENGLES_2
337  if (gles2gsg_cat.is_debug()) {
338  gles2gsg_cat.debug()
339 #else
340  if (glesgsg_cat.is_debug()) {
341  glesgsg_cat.debug()
342 #endif
343  << "EGL_VERSION = " << _egl_version_major << "." << _egl_version_minor
344  << "\n";
345  }
346 }
347 
348 /**
349  * This may be redefined by a derived class (e.g. glx or wgl) to get whatever
350  * further extensions strings may be appropriate to that interface, in
351  * addition to the GL extension strings return by glGetString().
352  */
353 void eglGraphicsStateGuardian::
354 get_extra_extensions() {
355  save_extensions(eglQueryString(_egl_display, EGL_EXTENSIONS));
356 }
357 
358 /**
359  * Returns the pointer to the GL extension function with the indicated name.
360  * It is the responsibility of the caller to ensure that the required
361  * extension is defined in the OpenGL runtime prior to calling this; it is an
362  * error to call this for a function that is not defined.
363  */
364 void *eglGraphicsStateGuardian::
365 do_get_extension_func(const char *name) {
366  return (void *)eglGetProcAddress(name);
367 }
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool egl_is_at_least_version(int major_version, int minor_version) const
Returns true if the runtime GLX version number is at least the indicated value, false otherwise.
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
Similar to MutexHolder, but for a light reentrant mutex.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void reset()
Resets all internal state as if the gsg were newly created.
void set_rgba_bits(int r, int g, int b, int a)
Convenience method for setting the red, green, blue and alpha bits in one go.
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
This class is the main interface to controlling the render process.
void get_properties(FrameBufferProperties &properties, bool &pbuffer_supported, bool &pixmap_supported, bool &slow, EGLConfig config)
Gets the FrameBufferProperties to match the indicated config.
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...
int get_quality(const FrameBufferProperties &reqs) const
Assumes that these properties are a description of a window.