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  // "slow" likely indicates no hardware acceleration.
124  properties.set_force_software(slow);
125  properties.set_force_hardware(!slow);
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  // This is set during window creation, but for now we have to pretend
227  // that we can honor the request, if we support the extension.
228  if (properties.get_srgb_color()) {
229  const char *extensions = eglQueryString(_egl_display, EGL_EXTENSIONS);
230  if (extensions != nullptr) {
231  vector_string tokens;
232  extract_words(extensions, tokens);
233 
234  if (std::find(tokens.begin(), tokens.end(), "EGL_KHR_gl_colorspace") != tokens.end()) {
235  best_props.set_srgb_color(true);
236  }
237  }
238  }
239 
240  _fbprops = best_props;
241  delete[] configs;
242  return;
243  }
244  }
245  // This really shouldn't happen, so I'm not too careful about cleanup.
246  egldisplay_cat.error()
247  << "Could not create EGL context!\n"
248  << get_egl_error_string(err) << "\n";
249  _fbconfig = 0;
250  _context = 0;
251  _visual = 0;
252  _visuals = 0;
253  }
254 
255  egldisplay_cat.error() <<
256  "Could not find a usable pixel format.\n";
257 
258  delete[] configs;
259 }
260 
261 /**
262  * Resets all internal state as if the gsg were newly created.
263  */
265 reset() {
266 #ifdef OPENGLES_2
267  GLES2GraphicsStateGuardian::reset();
268 #else
269  GLESGraphicsStateGuardian::reset();
270 #endif
271 
272  if (_gl_renderer == "Software Rasterizer") {
273  _fbprops.set_force_software(1);
274  _fbprops.set_force_hardware(0);
275  }
276 }
277 
278 /**
279  * Returns true if the runtime GLX version number is at least the indicated
280  * value, false otherwise.
281  */
283 egl_is_at_least_version(int major_version, int minor_version) const {
284  if (_egl_version_major < major_version) {
285  return false;
286  }
287  if (_egl_version_minor < minor_version) {
288  return false;
289  }
290  return true;
291 }
292 
293 /**
294  * Calls glFlush().
295  */
296 void eglGraphicsStateGuardian::
297 gl_flush() const {
298  // This call requires synchronization with X.
299  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
300 #ifdef OPENGLES_2
301  GLES2GraphicsStateGuardian::gl_flush();
302 #else
303  GLESGraphicsStateGuardian::gl_flush();
304 #endif
305 }
306 
307 /**
308  * Returns the result of glGetError().
309  */
310 GLenum eglGraphicsStateGuardian::
311 gl_get_error() const {
312  // This call requires synchronization with X.
313  LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
314 #ifdef OPENGLES_2
315  return GLES2GraphicsStateGuardian::gl_get_error();
316 #else
317  return GLESGraphicsStateGuardian::gl_get_error();
318 #endif
319 }
320 
321 /**
322  * Queries the runtime version of OpenGL in use.
323  */
324 void eglGraphicsStateGuardian::
325 query_gl_version() {
326 #ifdef OPENGLES_2
327  GLES2GraphicsStateGuardian::query_gl_version();
328 #else
329  GLESGraphicsStateGuardian::query_gl_version();
330 #endif
331 
332  // Calling eglInitialize on an already-initialized display will just provide
333  // us the version numbers.
334  if (!eglInitialize(_egl_display, &_egl_version_major, &_egl_version_minor)) {
335  egldisplay_cat.error() << "Failed to get EGL version number: "
336  << get_egl_error_string(eglGetError()) << "\n";
337  }
338 
339  // We output to glesgsg_cat instead of egldisplay_cat, since this is where
340  // the GL version has been output, and it's nice to see the two of these
341  // together.
342 #ifdef OPENGLES_2
343  if (gles2gsg_cat.is_debug()) {
344  gles2gsg_cat.debug()
345 #else
346  if (glesgsg_cat.is_debug()) {
347  glesgsg_cat.debug()
348 #endif
349  << "EGL_VERSION = " << _egl_version_major << "." << _egl_version_minor
350  << "\n";
351  }
352 }
353 
354 /**
355  * This may be redefined by a derived class (e.g. glx or wgl) to get whatever
356  * further extensions strings may be appropriate to that interface, in
357  * addition to the GL extension strings return by glGetString().
358  */
359 void eglGraphicsStateGuardian::
360 get_extra_extensions() {
361  save_extensions(eglQueryString(_egl_display, EGL_EXTENSIONS));
362 }
363 
364 /**
365  * Returns the pointer to the GL extension function with the indicated name.
366  * It is the responsibility of the caller to ensure that the required
367  * extension is defined in the OpenGL runtime prior to calling this; it is an
368  * error to call this for a function that is not defined.
369  */
370 void *eglGraphicsStateGuardian::
371 do_get_extension_func(const char *name) {
372  return (void *)eglGetProcAddress(name);
373 }
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:283
eglGraphicsStateGuardian::reset
virtual void reset()
Resets all internal state as if the gsg were newly created.
Definition: eglGraphicsStateGuardian.cxx:265
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
extract_words
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
Definition: string_utils.cxx:105
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.