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