Panda3D
eglGraphicsPipe.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 eglGraphicsPipe.cxx
10 * @author rdb
11 * @date 2009-05-21
12 */
13
14#include "eglGraphicsBuffer.h"
15#include "eglGraphicsPipe.h"
16#include "eglGraphicsPixmap.h"
17#include "eglGraphicsWindow.h"
19#include "config_egldisplay.h"
21
22#include <EGL/eglext.h>
23
24TypeHandle eglGraphicsPipe::_type_handle;
25
26/**
27 *
28 */
29eglGraphicsPipe::
30eglGraphicsPipe() {
31 // Check for client extensions.
32 vector_string extensions;
33 const char *ext_ptr = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
34 if (ext_ptr != nullptr) {
35 extract_words(ext_ptr, extensions);
36
37 if (egldisplay_cat.is_debug()) {
38 std::ostream &out = egldisplay_cat.debug()
39 << "Supported EGL client extensions:\n";
40
41 for (const std::string &extension : extensions) {
42 out << " " << extension << "\n";
43 }
44 }
45 }
46 else if (egldisplay_cat.is_debug()) {
47 eglGetError();
48 egldisplay_cat.debug()
49 << "EGL client extensions not supported.\n";
50 }
51
52 EGLint major, minor;
53
54 //NB. if the X11 display failed to open, _display will be 0, which is a valid
55 // input to eglGetDisplay - it means to open the default display.
56#ifdef USE_X11
57 _egl_display = eglGetDisplay((NativeDisplayType) _display);
58#else
59 _egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
60#endif
61 if (_egl_display && !eglInitialize(_egl_display, &major, &minor)) {
62 egldisplay_cat.warning()
63 << "Couldn't initialize the default EGL display: "
64 << get_egl_error_string(eglGetError()) << "\n";
65 _egl_display = EGL_NO_DISPLAY;
66 }
67
68 if (!_egl_display &&
69 std::find(extensions.begin(), extensions.end(), "EGL_EXT_platform_device") != extensions.end() &&
70 std::find(extensions.begin(), extensions.end(), "EGL_EXT_device_enumeration") != extensions.end()) {
71
72 PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
73 (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
74
75 EGLint num_devices = 0;
76 if (eglQueryDevicesEXT != nullptr &&
77 eglQueryDevicesEXT(0, nullptr, &num_devices) &&
78 num_devices > 0) {
79 EGLDeviceEXT *devices = (EGLDeviceEXT *)alloca(sizeof(EGLDeviceEXT) * num_devices);
80 eglQueryDevicesEXT(num_devices, devices, &num_devices);
81
82 if (egldisplay_cat.is_debug()) {
83 egldisplay_cat.debug()
84 << "Found " << num_devices << " EGL devices.\n";
85 }
86
87 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
88 (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
89
90 if (eglGetPlatformDisplayEXT != nullptr) {
91 for (EGLint i = 0; i < num_devices && !_egl_display; ++i) {
92 _egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devices[i], nullptr);
93
94 if (_egl_display && !eglInitialize(_egl_display, &major, &minor)) {
95 egldisplay_cat.warning()
96 << "Couldn't initialize EGL platform display " << i << ": "
97 << get_egl_error_string(eglGetError()) << "\n";
98 _egl_display = EGL_NO_DISPLAY;
99 }
100 }
101 }
102 }
103 }
104
105 if (!_egl_display) {
106 egldisplay_cat.error()
107 << "Failed to find or initialize a suitable EGL display connection.\n";
108 _is_valid = false;
109 return;
110 }
111
112 if (egldisplay_cat.is_debug()) {
113 egldisplay_cat.debug()
114 << "Successfully initialized EGL display, got version " << major << "." << minor << "\n";
115 }
116
117#if defined(OPENGLES_1) || defined(OPENGLES_2)
118 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
119 egldisplay_cat.error()
120 << "Couldn't bind EGL to the OpenGL ES API: "
121 << get_egl_error_string(eglGetError()) << "\n";
122#else
123 if (!eglBindAPI(EGL_OPENGL_API)) {
124 egldisplay_cat.error()
125 << "Couldn't bind EGL to the OpenGL API: "
126 << get_egl_error_string(eglGetError()) << "\n";
127#endif
128 _is_valid = false;
129 return;
130 }
131
132 // Even if we don't have an X11 display, we can still render headless.
133 _is_valid = true;
134}
135
136/**
137 *
138 */
139eglGraphicsPipe::
140~eglGraphicsPipe() {
141 if (_egl_display) {
142 if (!eglTerminate(_egl_display)) {
143 egldisplay_cat.error() << "Failed to terminate EGL display: "
144 << get_egl_error_string(eglGetError()) << "\n";
145 }
146 }
147}
148
149/**
150 * Returns the name of the rendering interface associated with this
151 * GraphicsPipe. This is used to present to the user to allow him/her to
152 * choose between several possible GraphicsPipes available on a particular
153 * platform, so the name should be meaningful and unique for a given platform.
154 */
156get_interface_name() const {
157#if defined(OPENGLES_1) || defined(OPENGLES_2)
158 return "OpenGL ES";
159#else
160 return "OpenGL";
161#endif
162}
163
164/**
165 * This function is passed to the GraphicsPipeSelection object to allow the
166 * user to make a default eglGraphicsPipe.
167 */
168PT(GraphicsPipe) eglGraphicsPipe::
169pipe_constructor() {
170 return new eglGraphicsPipe;
171}
172
173/**
174 * Creates a new window on the pipe, if possible.
175 */
176PT(GraphicsOutput) eglGraphicsPipe::
177make_output(const std::string &name,
178 const FrameBufferProperties &fb_prop,
179 const WindowProperties &win_prop,
180 int flags,
181 GraphicsEngine *engine,
183 GraphicsOutput *host,
184 int retry,
185 bool &precertify) {
186
187 if (!_is_valid) {
188 return nullptr;
189 }
190
191 eglGraphicsStateGuardian *eglgsg = 0;
192 if (gsg != 0) {
193 DCAST_INTO_R(eglgsg, gsg, nullptr);
194 }
195
196 bool support_rtt;
197 support_rtt = false;
198 /*
199 Currently, no support for eglGraphicsBuffer render-to-texture.
200 if (eglgsg) {
201 support_rtt =
202 eglgsg -> get_supports_render_texture() &&
203 support_render_texture;
204 }
205 */
206
207 // First thing to try: an eglGraphicsWindow
208
209 if (retry == 0) {
210#ifdef USE_X11
211 if (!_display) {
212 return nullptr;
213 }
214 if (((flags&BF_require_parasite)!=0)||
215 ((flags&BF_refuse_window)!=0)||
216 ((flags&BF_resizeable)!=0)||
217 ((flags&BF_size_track_host)!=0)||
218 ((flags&BF_rtt_cumulative)!=0)||
219 ((flags&BF_can_bind_color)!=0)||
220 ((flags&BF_can_bind_every)!=0)) {
221 return nullptr;
222 }
223 return new eglGraphicsWindow(engine, this, name, fb_prop, win_prop,
224 flags, gsg, host);
225#else
226 return nullptr;
227#endif
228 }
229
230 // Second thing to try: a GL(ES(2))GraphicsBuffer
231 if (retry == 1) {
232 if ((host==0)||
233 // (!gl_support_fbo)||
234 ((flags&BF_require_parasite)!=0)||
235 ((flags&BF_require_window)!=0)) {
236 return nullptr;
237 }
238 // Early failure - if we are sure that this buffer WONT meet specs, we can
239 // bail out early.
240 if ((flags & BF_fb_props_optional)==0) {
241 if (fb_prop.get_indexed_color() > 0 ||
242 fb_prop.get_back_buffers() > 0 ||
243 fb_prop.get_accum_bits() > 0) {
244 return nullptr;
245 }
246 }
247 // Early success - if we are sure that this buffer WILL meet specs, we can
248 // precertify it.
249 if ((eglgsg != 0) &&
250 (eglgsg->is_valid()) &&
251 (!eglgsg->needs_reset()) &&
252 (eglgsg->_supports_framebuffer_object) &&
253 (eglgsg->_glDrawBuffers != 0)&&
254 (fb_prop.is_basic())) {
255 precertify = true;
256 }
257#ifdef OPENGLES_2
258 return new GLES2GraphicsBuffer(engine, this, name, fb_prop, win_prop,
259 flags, gsg, host);
260#elif defined(OPENGLES_1)
261 return new GLESGraphicsBuffer(engine, this, name, fb_prop, win_prop,
262 flags, gsg, host);
263#else
264 return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
265 flags, gsg, host);
266#endif
267 }
268
269 // Third thing to try: a eglGraphicsBuffer
270 if (retry == 2) {
271 if (((flags&BF_require_parasite)!=0)||
272 ((flags&BF_require_window)!=0)||
273 ((flags&BF_resizeable)!=0)||
274 ((flags&BF_size_track_host)!=0)) {
275 return nullptr;
276 }
277
278 if (!support_rtt) {
279 if (((flags&BF_rtt_cumulative)!=0)||
280 ((flags&BF_can_bind_every)!=0)) {
281 // If we require Render-to-Texture, but can't be sure we support it,
282 // bail.
283 return nullptr;
284 }
285 }
286
287 return new eglGraphicsBuffer(engine, this, name, fb_prop, win_prop,
288 flags, gsg, host);
289 }
290
291 // Fourth thing to try: an eglGraphicsPixmap.
292 if (retry == 3) {
293#ifdef USE_X11
294 if (!_display) {
295 return nullptr;
296 }
297 if (((flags&BF_require_parasite)!=0)||
298 ((flags&BF_require_window)!=0)||
299 ((flags&BF_resizeable)!=0)||
300 ((flags&BF_size_track_host)!=0)) {
301 return nullptr;
302 }
303
304 if (((flags&BF_rtt_cumulative)!=0)||
305 ((flags&BF_can_bind_every)!=0)) {
306 return nullptr;
307 }
308
309 return new eglGraphicsPixmap(engine, this, name, fb_prop, win_prop,
310 flags, gsg, host);
311#else
312 return nullptr;
313#endif
314 }
315
316 // Nothing else left to try.
317 return nullptr;
318}
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool is_basic() const
Returns true if the properties are extremely basic.
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
Encapsulates all the communication with a particular instance of a given rendering backend.
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 window before we o...
An offscreen buffer in the EGL environment.
This graphics pipe represents the interface for creating OpenGL ES graphics windows on an X-based (e....
virtual std::string get_interface_name() const
Returns the name of the rendering interface associated with this GraphicsPipe.
A tiny specialization on GLESGraphicsStateGuardian to add some egl-specific information.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.