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