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