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  */
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  */
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 }
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
bool create_context()
Creates the context based on the config previously obtained in choose_pixel_format.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
virtual void reset()
Resets all internal state as if the gsg were newly created.
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
void get_properties(FrameBufferProperties &properties, bool &pbuffer_supported, bool &pixmap_supported, bool &slow, EGLConfig config)
Gets the FrameBufferProperties to match the indicated config.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
void destroy_context()
Destroys the context previously created by create_context.
This class is the main interface to controlling the render process.
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.