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
14 #include "androidGraphicsStateGuardian.h"
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 */
63 void AndroidGraphicsStateGuardian::
64 get_properties(FrameBufferProperties &properties,
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 */
126 void AndroidGraphicsStateGuardian::
127 choose_pixel_format(const FrameBufferProperties &properties,
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 */
221 bool AndroidGraphicsStateGuardian::
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 */
249 void AndroidGraphicsStateGuardian::
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 */
269 void AndroidGraphicsStateGuardian::
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 */
291 bool AndroidGraphicsStateGuardian::
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 }
androidGraphicsStateGuardian.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AndroidGraphicsStateGuardian
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
Definition: androidGraphicsStateGuardian.h:27
AndroidGraphicsStateGuardian::create_context
bool create_context()
Creates the context based on the config previously obtained in choose_pixel_format.
Definition: androidGraphicsStateGuardian.cxx:222
AndroidGraphicsStateGuardian::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: androidGraphicsStateGuardian.cxx:64
AndroidGraphicsStateGuardian::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: androidGraphicsStateGuardian.cxx:292
AndroidGraphicsStateGuardian::reset
virtual void reset()
Resets all internal state as if the gsg were newly created.
Definition: androidGraphicsStateGuardian.cxx:270
AndroidGraphicsStateGuardian::destroy_context
void destroy_context()
Destroys the context previously created by create_context.
Definition: androidGraphicsStateGuardian.cxx:250
AndroidGraphicsStateGuardian::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.
Definition: androidGraphicsStateGuardian.cxx:127
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
FrameBufferProperties::clear
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
Definition: frameBufferProperties.cxx:185
FrameBufferProperties::get_quality
int get_quality(const FrameBufferProperties &reqs) const
Assumes that these properties are a description of a window.
Definition: frameBufferProperties.cxx:438
GraphicsEngine
This class is the main interface to controlling the render process.
Definition: graphicsEngine.h:53
GraphicsPipe
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
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
config_androiddisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lightReMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.