Panda3D
Loading...
Searching...
No Matches
eglGraphicsStateGuardian.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 eglGraphicsStateGuardian.cxx
10 * @author rdb
11 * @date 2009-05-21
12 */
13
15#include "config_egldisplay.h"
16#include "lightReMutexHolder.h"
17
18#include <dlfcn.h>
19
20TypeHandle eglGraphicsStateGuardian::_type_handle;
21
22/**
23 *
24 */
25eglGraphicsStateGuardian::
26eglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
27 eglGraphicsStateGuardian *share_with) :
28 BaseGraphicsStateGuardian(engine, pipe)
29{
30 _share_context=0;
31 _context=0;
32 _egl_display=0;
33 _fbconfig=0;
34
35 if (share_with != nullptr) {
36 _prepared_objects = share_with->get_prepared_objects();
37 _share_context = share_with->_context;
38 }
39}
40
41/**
42 *
43 */
44eglGraphicsStateGuardian::
45~eglGraphicsStateGuardian() {
46 if (_context != (EGLContext)nullptr) {
47 if (!eglDestroyContext(_egl_display, _context)) {
48 egldisplay_cat.error() << "Failed to destroy EGL context: "
49 << get_egl_error_string(eglGetError()) << "\n";
50 }
51 _context = (EGLContext)nullptr;
52 }
53}
54
55/**
56 * Gets the FrameBufferProperties to match the indicated config.
57 */
60 bool &pbuffer_supported, bool &pixmap_supported,
61 bool &slow, EGLConfig config) {
62
63 properties.clear();
64
65 // Now update our framebuffer_mode and bit depth appropriately.
66 EGLint red_size, green_size, blue_size,
67 alpha_size,
68 depth_size, stencil_size, samples, surface_type, caveat;
69
70 eglGetConfigAttrib(_egl_display, config, EGL_RED_SIZE, &red_size);
71 eglGetConfigAttrib(_egl_display, config, EGL_GREEN_SIZE, &green_size);
72 eglGetConfigAttrib(_egl_display, config, EGL_BLUE_SIZE, &blue_size);
73 eglGetConfigAttrib(_egl_display, config, EGL_ALPHA_SIZE, &alpha_size);
74 eglGetConfigAttrib(_egl_display, config, EGL_DEPTH_SIZE, &depth_size);
75 eglGetConfigAttrib(_egl_display, config, EGL_STENCIL_SIZE, &stencil_size);
76 eglGetConfigAttrib(_egl_display, config, EGL_SAMPLES, &samples);
77 eglGetConfigAttrib(_egl_display, config, EGL_SURFACE_TYPE, &surface_type);
78 eglGetConfigAttrib(_egl_display, config, EGL_CONFIG_CAVEAT, &caveat);
79 int err = eglGetError();
80 if (err != EGL_SUCCESS) {
81 egldisplay_cat.error() << "Failed to get EGL config attrib: "
82 << get_egl_error_string(err) << "\n";
83 }
84
85 pbuffer_supported = false;
86 if ((surface_type & EGL_PBUFFER_BIT)!=0) {
87 pbuffer_supported = true;
88 }
89
90 pixmap_supported = false;
91 if ((surface_type & EGL_PIXMAP_BIT)!=0) {
92 pixmap_supported = true;
93 }
94
95 slow = false;
96 if (caveat == EGL_SLOW_CONFIG) {
97 slow = true;
98 }
99
100 properties.set_back_buffers(1);
101 properties.set_rgb_color(1);
102 properties.set_rgba_bits(red_size, green_size, blue_size, alpha_size);
103 properties.set_stencil_bits(stencil_size);
104 properties.set_depth_bits(depth_size);
105 properties.set_multisamples(samples);
106
107 // "slow" likely indicates no hardware acceleration.
108 properties.set_force_software(slow);
109 properties.set_force_hardware(!slow);
110}
111
112/**
113 * Selects a visual or fbconfig for all the windows and buffers that use this
114 * gsg. Also creates the GL context and obtains the visual.
115 */
118 eglGraphicsPipe *egl_pipe, bool need_window,
119 bool need_pbuffer, bool need_pixmap) {
120
121 _egl_display = egl_pipe->get_egl_display();
122 _context = 0;
123 _fbconfig = 0;
124 _fbprops.clear();
125
126 int attrib_list[] = {
127#if defined(OPENGLES_1)
128 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
129#elif defined(OPENGLES_2)
130 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
131#else
132 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
133#endif
134 EGL_SURFACE_TYPE, need_window ? EGL_WINDOW_BIT : EGL_DONT_CARE,
135 EGL_NONE
136 };
137
138 // First get the number of matching configurations, so we know how much
139 // memory to allocate.
140 int num_configs = 0, returned_configs;
141 if (!eglChooseConfig(_egl_display, attrib_list, nullptr, num_configs, &returned_configs) || returned_configs <= 0) {
142 egldisplay_cat.error() << "eglChooseConfig failed: "
143 << get_egl_error_string(eglGetError()) << "\n";
144 return;
145 }
146
147 num_configs = returned_configs;
148 EGLConfig *configs = new EGLConfig[num_configs];
149
150 if (!eglChooseConfig(_egl_display, attrib_list, configs, num_configs, &returned_configs) || returned_configs <= 0) {
151 egldisplay_cat.error() << "eglChooseConfig failed: "
152 << get_egl_error_string(eglGetError()) << "\n";
153 delete[] configs;
154 return;
155 }
156
157 int best_quality = 0;
158 int best_result = 0;
159 FrameBufferProperties best_props;
160
161 for (int i = 0; i < num_configs; ++i) {
162 FrameBufferProperties fbprops;
163 bool pbuffer_supported, pixmap_supported, slow;
164 get_properties(fbprops, pbuffer_supported, pixmap_supported,
165 slow, configs[i]);
166 // We're not protecting this code by an is_debug() check, because if we
167 // do, some weird compiler bug appears and somehow makes the quality
168 // always 0.
169 const char *pbuffertext = pbuffer_supported ? " (pbuffer)" : "";
170 const char *pixmaptext = pixmap_supported ? " (pixmap)" : "";
171 const char *slowtext = slow ? " (slow)" : "";
172 egldisplay_cat.debug()
173 << i << ": " << fbprops << pbuffertext << pixmaptext << slowtext << "\n";
174 int quality = fbprops.get_quality(properties);
175 if ((quality > 0)&&(slow)) quality -= 10000000;
176
177 if (need_pbuffer && !pbuffer_supported) {
178 continue;
179 }
180 if (need_pixmap && !pixmap_supported) {
181 continue;
182 }
183
184 if (quality > best_quality) {
185 best_quality = quality;
186 best_result = i;
187 best_props = fbprops;
188 }
189 }
190#ifdef USE_X11
191 X11_Display *display = egl_pipe->get_display();
192 if (display) {
193 int screen = egl_pipe->get_screen();
194 int depth = DefaultDepth(display, screen);
195 _visual = new XVisualInfo;
196 XMatchVisualInfo(display, screen, depth, TrueColor, _visual);
197 }
198#endif
199
200 if (best_quality > 0) {
201 egldisplay_cat.debug()
202 << "Chosen config " << best_result << ": " << best_props << "\n";
203 _fbconfig = configs[best_result];
204
205 EGLint attribs[32];
206 int n = 0;
207
208#ifdef OPENGLES_2
209 attribs[n++] = EGL_CONTEXT_CLIENT_VERSION;
210 attribs[n++] = 2;
211#elif defined(OPENGLES_1)
212#else // Regular OpenGL
213 if (gl_version.get_num_words() > 0) {
214 attribs[n++] = EGL_CONTEXT_MAJOR_VERSION;
215 attribs[n++] = gl_version[0];
216 if (gl_version.get_num_words() > 1) {
217 attribs[n++] = EGL_CONTEXT_MINOR_VERSION;
218 attribs[n++] = gl_version[1];
219 }
220 }
221 if (gl_debug) {
222 attribs[n++] = EGL_CONTEXT_OPENGL_DEBUG;
223 attribs[n++] = EGL_TRUE;
224 }
225 if (gl_forward_compatible) {
226 attribs[n++] = EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE;
227 attribs[n++] = EGL_TRUE;
228 }
229#endif
230 attribs[n] = EGL_NONE;
231
232 _context = eglCreateContext(_egl_display, _fbconfig, _share_context, (n > 0) ? attribs : nullptr);
233
234 int err = eglGetError();
235 if (_context && err == EGL_SUCCESS) {
236#ifdef USE_X11
237 if (!display || _visual)
238#endif
239 {
240 // This is set during window creation, but for now we have to pretend
241 // that we can honor the request, if we support the extension.
242 if (properties.get_srgb_color()) {
243 const char *extensions = eglQueryString(_egl_display, EGL_EXTENSIONS);
244 if (extensions != nullptr) {
245 vector_string tokens;
246 extract_words(extensions, tokens);
247
248 if (std::find(tokens.begin(), tokens.end(), "EGL_KHR_gl_colorspace") != tokens.end()) {
249 best_props.set_srgb_color(true);
250 }
251 }
252 }
253
254 _fbprops = best_props;
255 delete[] configs;
256 return;
257 }
258 }
259 // This really shouldn't happen, so I'm not too careful about cleanup.
260 egldisplay_cat.error()
261 << "Could not create EGL context!\n"
262 << get_egl_error_string(err) << "\n";
263 _fbconfig = 0;
264 _context = 0;
265#ifdef USE_X11
266 _visual = 0;
267#endif
268 }
269
270 egldisplay_cat.error() <<
271 "Could not find a usable pixel format.\n";
272
273 delete[] configs;
274}
275
276/**
277 * Resets all internal state as if the gsg were newly created.
278 */
280reset() {
281 BaseGraphicsStateGuardian::reset();
282
283 if (_gl_renderer == "Software Rasterizer") {
284 _fbprops.set_force_software(1);
285 _fbprops.set_force_hardware(0);
286 }
287}
288
289/**
290 * Returns true if the runtime GLX version number is at least the indicated
291 * value, false otherwise.
292 */
294egl_is_at_least_version(int major_version, int minor_version) const {
295 if (_egl_version_major < major_version) {
296 return false;
297 }
298 if (_egl_version_minor < minor_version) {
299 return false;
300 }
301 return true;
302}
303
304/**
305 * Calls glFlush().
306 */
307void eglGraphicsStateGuardian::
308gl_flush() const {
309#ifdef USE_X11
310 // This call requires synchronization with X.
311 LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
312#endif
313 BaseGraphicsStateGuardian::gl_flush();
314}
315
316/**
317 * Returns the result of glGetError().
318 */
319GLenum eglGraphicsStateGuardian::
320gl_get_error() const {
321#ifdef USE_X11
322 // This call requires synchronization with X.
323 LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
324#endif
325 return BaseGraphicsStateGuardian::gl_get_error();
326}
327
328/**
329 * Queries the runtime version of OpenGL in use.
330 */
331void eglGraphicsStateGuardian::
332query_gl_version() {
333 BaseGraphicsStateGuardian::query_gl_version();
334
335 // Calling eglInitialize on an already-initialized display will just provide
336 // us the version numbers.
337 if (!eglInitialize(_egl_display, &_egl_version_major, &_egl_version_minor)) {
338 egldisplay_cat.error() << "Failed to get EGL version number: "
339 << get_egl_error_string(eglGetError()) << "\n";
340 }
341
342 // We output to glesgsg_cat instead of egldisplay_cat, since this is where
343 // the GL version has been output, and it's nice to see the two of these
344 // together.
345#ifdef OPENGLES_2
346 if (gles2gsg_cat.is_debug()) {
347 gles2gsg_cat.debug()
348#elif defined(OPENGLES_1)
349 if (glesgsg_cat.is_debug()) {
350 glesgsg_cat.debug()
351#else
352 if (glgsg_cat.is_debug()) {
353 glgsg_cat.debug()
354#endif
355 << "EGL_VERSION = " << _egl_version_major << "." << _egl_version_minor
356 << "\n";
357 }
358}
359
360/**
361 * This may be redefined by a derived class (e.g. glx or wgl) to get whatever
362 * further extensions strings may be appropriate to that interface, in
363 * addition to the GL extension strings return by glGetString().
364 */
365void eglGraphicsStateGuardian::
366get_extra_extensions() {
367 save_extensions(eglQueryString(_egl_display, EGL_EXTENSIONS));
368}
369
370/**
371 * Returns the pointer to the GL extension function with the indicated name.
372 * It is the responsibility of the caller to ensure that the required
373 * extension is defined in the OpenGL runtime prior to calling this; it is an
374 * error to call this for a function that is not defined.
375 */
376void *eglGraphicsStateGuardian::
377do_get_extension_func(const char *name) {
378 return (void *)eglGetProcAddress(name);
379}
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.
Similar to MutexHolder, but for a light reentrant mutex.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
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.
void choose_pixel_format(const FrameBufferProperties &properties, eglGraphicsPipe *egl_pipe, bool need_window, bool need_pbuffer, bool need_pixmap)
Selects a visual or fbconfig for all the windows and buffers that use this gsg.
void get_properties(FrameBufferProperties &properties, bool &pbuffer_supported, bool &pixmap_supported, bool &slow, EGLConfig config)
Gets the FrameBufferProperties to match the indicated config.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.