Panda3D
Loading...
Searching...
No Matches
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
16#include "lightReMutexHolder.h"
17
18#include <dlfcn.h>
19
20TypeHandle AndroidGraphicsStateGuardian::_type_handle;
21
22/**
23 *
24 */
25AndroidGraphicsStateGuardian::
26AndroidGraphicsStateGuardian(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 */
49AndroidGraphicsStateGuardian::
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) {
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 */
270reset() {
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 */
292egl_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 */
305void AndroidGraphicsStateGuardian::
306gl_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 */
317GLenum AndroidGraphicsStateGuardian::
318gl_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 */
329void AndroidGraphicsStateGuardian::
330query_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 */
364void AndroidGraphicsStateGuardian::
365get_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 */
375void *AndroidGraphicsStateGuardian::
376do_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.
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.