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 }
FrameBufferProperties
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
Definition: frameBufferProperties.h:26
FrameBufferProperties::set_rgba_bits
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.
Definition: frameBufferProperties.I:255
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
FrameBufferProperties::clear
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
Definition: frameBufferProperties.cxx:185
GraphicsEngine
This class is the main interface to controlling the render process.
Definition: graphicsEngine.h:53
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
eglGraphicsStateGuardian::egl_is_at_least_version
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.
Definition: eglGraphicsStateGuardian.cxx:277
eglGraphicsStateGuardian::reset
virtual void reset()
Resets all internal state as if the gsg were newly created.
Definition: eglGraphicsStateGuardian.cxx:251
eglGraphicsStateGuardian::choose_pixel_format
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.
Definition: eglGraphicsStateGuardian.cxx:133
GraphicsPipe
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
eglGraphicsStateGuardian.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eglGraphicsStateGuardian::get_properties
void get_properties(FrameBufferProperties &properties, bool &pbuffer_supported, bool &pixmap_supported, bool &slow, EGLConfig config)
Gets the FrameBufferProperties to match the indicated config.
Definition: eglGraphicsStateGuardian.cxx:70
FrameBufferProperties::get_quality
int get_quality(const FrameBufferProperties &reqs) const
Assumes that these properties are a description of a window.
Definition: frameBufferProperties.cxx:438
get_egl_error_string
const std::string get_egl_error_string(int error)
Returns the given EGL error as string.
Definition: config_androiddisplay.cxx:67
config_egldisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eglGraphicsStateGuardian
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
Definition: eglGraphicsStateGuardian.h:28
lightReMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.