Panda3D
Loading...
Searching...
No Matches
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
24static ConfigVariableInt egl_device_index
25("egl-device-index", -1,
26 PRC_DESC("Selects which EGL device index is used to create the EGL display in "
27 "a headless configuration. The special value -1 selects the default "
28 "device."));
29
30TypeHandle eglGraphicsPipe::_type_handle;
31
32/**
33 *
34 */
35eglGraphicsPipe::
36eglGraphicsPipe() {
37 // Check for client extensions.
38 vector_string extensions;
39 bool supports_platform_device = false;
40 bool supports_device_enumeration = false;
41 const char *ext_ptr = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
42 if (ext_ptr != nullptr) {
43 extract_words(ext_ptr, extensions);
44
45 if (egldisplay_cat.is_debug()) {
46 std::ostream &out = egldisplay_cat.debug()
47 << "Supported EGL client extensions:\n";
48
49 for (const std::string &extension : extensions) {
50 out << " " << extension << "\n";
51 }
52 }
53
54 if (std::find(extensions.begin(), extensions.end(), "EGL_EXT_platform_device") != extensions.end()) {
55 supports_platform_device = true;
56 }
57 if (std::find(extensions.begin(), extensions.end(), "EGL_EXT_device_enumeration") != extensions.end()) {
58 supports_device_enumeration = true;
59 }
60 }
61 else if (egldisplay_cat.is_debug()) {
62 eglGetError();
63 egldisplay_cat.debug()
64 << "EGL client extensions not supported.\n";
65 }
66
67 EGLint major, minor;
68
69 int index = egl_device_index.get_value();
70 if (index >= 0 && supports_platform_device && supports_device_enumeration) {
71 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
72 (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
73
74 PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
75 (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
76
77 EGLint num_devices = 0;
78 if (eglQueryDevicesEXT != nullptr &&
79 eglQueryDevicesEXT(0, nullptr, &num_devices) &&
80 num_devices > 0) {
81 EGLDeviceEXT *devices = (EGLDeviceEXT *)alloca(sizeof(EGLDeviceEXT) * num_devices);
82 eglQueryDevicesEXT(num_devices, devices, &num_devices);
83
84 if (index >= num_devices) {
85 egldisplay_cat.error()
86 << "Requested EGL device index " << index << " does not exist ("
87 << "there are only " << num_devices << " devices)\n";
88 _is_valid = false;
89 return;
90 }
91
92 if (egldisplay_cat.is_debug()) {
93 egldisplay_cat.debug()
94 << "Found " << num_devices << " EGL devices, using device index "
95 << index << ".\n";
96 }
97
98 _egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devices[index], nullptr);
99
100 if (_egl_display && !eglInitialize(_egl_display, &major, &minor)) {
101 egldisplay_cat.error()
102 << "Couldn't initialize EGL platform display " << index << ": "
103 << get_egl_error_string(eglGetError()) << "\n";
104 _egl_display = EGL_NO_DISPLAY;
105 }
106 }
107 }
108 else {
109 //NB. if the X11 display failed to open, _display will be 0, which is a valid
110 // input to eglGetDisplay - it means to open the default display.
111 #ifdef USE_X11
112 _egl_display = eglGetDisplay((NativeDisplayType) _display);
113 #else
114 _egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
115 #endif
116 if (_egl_display && !eglInitialize(_egl_display, &major, &minor)) {
117 egldisplay_cat.warning()
118 << "Couldn't initialize the default EGL display: "
119 << get_egl_error_string(eglGetError()) << "\n";
120 _egl_display = EGL_NO_DISPLAY;
121 }
122
123 if (!_egl_display && supports_platform_device && supports_device_enumeration) {
124 PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
125 (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
126
127 EGLint num_devices = 0;
128 if (eglQueryDevicesEXT != nullptr &&
129 eglQueryDevicesEXT(0, nullptr, &num_devices) &&
130 num_devices > 0) {
131 EGLDeviceEXT *devices = (EGLDeviceEXT *)alloca(sizeof(EGLDeviceEXT) * num_devices);
132 eglQueryDevicesEXT(num_devices, devices, &num_devices);
133
134 if (egldisplay_cat.is_debug()) {
135 egldisplay_cat.debug()
136 << "Found " << num_devices << " EGL devices.\n";
137 }
138
139 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
140 (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
141
142 if (eglGetPlatformDisplayEXT != nullptr) {
143 for (EGLint i = 0; i < num_devices && !_egl_display; ++i) {
144 _egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devices[i], nullptr);
145
146 if (_egl_display && !eglInitialize(_egl_display, &major, &minor)) {
147 egldisplay_cat.warning()
148 << "Couldn't initialize EGL platform display " << i << ": "
149 << get_egl_error_string(eglGetError()) << "\n";
150 _egl_display = EGL_NO_DISPLAY;
151 }
152 }
153 }
154 }
155 }
156 }
157
158 if (!_egl_display) {
159 egldisplay_cat.error()
160 << "Failed to find or initialize a suitable EGL display connection.\n";
161 _is_valid = false;
162 return;
163 }
164
165 if (egldisplay_cat.is_debug()) {
166 egldisplay_cat.debug()
167 << "Successfully initialized EGL display, got version " << major << "." << minor << "\n";
168 }
169
170#if defined(OPENGLES_1) || defined(OPENGLES_2)
171 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
172 egldisplay_cat.error()
173 << "Couldn't bind EGL to the OpenGL ES API: "
174 << get_egl_error_string(eglGetError()) << "\n";
175#else
176 if (!eglBindAPI(EGL_OPENGL_API)) {
177 egldisplay_cat.error()
178 << "Couldn't bind EGL to the OpenGL API: "
179 << get_egl_error_string(eglGetError()) << "\n";
180#endif
181 _is_valid = false;
182 return;
183 }
184
185 // Even if we don't have an X11 display, we can still render headless.
186 _is_valid = true;
187}
188
189/**
190 *
191 */
192eglGraphicsPipe::
193~eglGraphicsPipe() {
194 if (_egl_display) {
195 if (!eglTerminate(_egl_display)) {
196 egldisplay_cat.error() << "Failed to terminate EGL display: "
197 << get_egl_error_string(eglGetError()) << "\n";
198 }
199 }
200}
201
202/**
203 * Returns the name of the rendering interface associated with this
204 * GraphicsPipe. This is used to present to the user to allow him/her to
205 * choose between several possible GraphicsPipes available on a particular
206 * platform, so the name should be meaningful and unique for a given platform.
207 */
209get_interface_name() const {
210#if defined(OPENGLES_1) || defined(OPENGLES_2)
211 return "OpenGL ES";
212#else
213 return "OpenGL";
214#endif
215}
216
217/**
218 * This function is passed to the GraphicsPipeSelection object to allow the
219 * user to make a default eglGraphicsPipe.
220 */
221PT(GraphicsPipe) eglGraphicsPipe::
222pipe_constructor() {
223 return new eglGraphicsPipe;
224}
225
226/**
227 * Creates a new window on the pipe, if possible.
228 */
229PT(GraphicsOutput) eglGraphicsPipe::
230make_output(const std::string &name,
231 const FrameBufferProperties &fb_prop,
232 const WindowProperties &win_prop,
233 int flags,
234 GraphicsEngine *engine,
236 GraphicsOutput *host,
237 int retry,
238 bool &precertify) {
239
240 if (!_is_valid) {
241 return nullptr;
242 }
243
244 eglGraphicsStateGuardian *eglgsg = 0;
245 if (gsg != 0) {
246 DCAST_INTO_R(eglgsg, gsg, nullptr);
247 }
248
249 bool support_rtt;
250 support_rtt = false;
251 /*
252 Currently, no support for eglGraphicsBuffer render-to-texture.
253 if (eglgsg) {
254 support_rtt =
255 eglgsg -> get_supports_render_texture() &&
256 support_render_texture;
257 }
258 */
259
260 // First thing to try: an eglGraphicsWindow
261
262 if (retry == 0) {
263#ifdef USE_X11
264 if (!_display) {
265 return nullptr;
266 }
267 if (((flags&BF_require_parasite)!=0)||
268 ((flags&BF_refuse_window)!=0)||
269 ((flags&BF_resizeable)!=0)||
270 ((flags&BF_size_track_host)!=0)||
271 ((flags&BF_rtt_cumulative)!=0)||
272 ((flags&BF_can_bind_color)!=0)||
273 ((flags&BF_can_bind_every)!=0)) {
274 return nullptr;
275 }
276 return new eglGraphicsWindow(engine, this, name, fb_prop, win_prop,
277 flags, gsg, host);
278#else
279 return nullptr;
280#endif
281 }
282
283 // Second thing to try: a GL(ES(2))GraphicsBuffer
284 if (retry == 1) {
285 if ((host==0)||
286 // (!gl_support_fbo)||
287 ((flags&BF_require_parasite)!=0)||
288 ((flags&BF_require_window)!=0)) {
289 return nullptr;
290 }
291 // Early failure - if we are sure that this buffer WONT meet specs, we can
292 // bail out early.
293 if ((flags & BF_fb_props_optional)==0) {
294 if (fb_prop.get_indexed_color() > 0 ||
295 fb_prop.get_back_buffers() > 0 ||
296 fb_prop.get_accum_bits() > 0) {
297 return nullptr;
298 }
299 }
300 // Early success - if we are sure that this buffer WILL meet specs, we can
301 // precertify it.
302 if ((eglgsg != 0) &&
303 (eglgsg->is_valid()) &&
304 (!eglgsg->needs_reset()) &&
305 (eglgsg->_supports_framebuffer_object) &&
306 (eglgsg->_glDrawBuffers != 0)&&
307 (fb_prop.is_basic())) {
308 precertify = true;
309 }
310#ifdef OPENGLES_2
311 return new GLES2GraphicsBuffer(engine, this, name, fb_prop, win_prop,
312 flags, gsg, host);
313#elif defined(OPENGLES_1)
314 return new GLESGraphicsBuffer(engine, this, name, fb_prop, win_prop,
315 flags, gsg, host);
316#else
317 return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop,
318 flags, gsg, host);
319#endif
320 }
321
322 // Third thing to try: a eglGraphicsBuffer
323 if (retry == 2) {
324 if (((flags&BF_require_parasite)!=0)||
325 ((flags&BF_require_window)!=0)||
326 ((flags&BF_size_track_host)!=0)) {
327 return nullptr;
328 }
329
330 if (!support_rtt) {
331 if (((flags&BF_rtt_cumulative)!=0)||
332 ((flags&BF_can_bind_every)!=0)) {
333 // If we require Render-to-Texture, but can't be sure we support it,
334 // bail.
335 return nullptr;
336 }
337 }
338
339 return new eglGraphicsBuffer(engine, this, name, fb_prop, win_prop,
340 flags, gsg, host);
341 }
342
343 // Fourth thing to try: an eglGraphicsPixmap.
344 if (retry == 3) {
345#ifdef USE_X11
346 if (!_display) {
347 return nullptr;
348 }
349 if (((flags&BF_require_parasite)!=0)||
350 ((flags&BF_require_window)!=0)||
351 ((flags&BF_resizeable)!=0)||
352 ((flags&BF_size_track_host)!=0)) {
353 return nullptr;
354 }
355
356 if (((flags&BF_rtt_cumulative)!=0)||
357 ((flags&BF_can_bind_every)!=0)) {
358 return nullptr;
359 }
360
361 return new eglGraphicsPixmap(engine, this, name, fb_prop, win_prop,
362 flags, gsg, host);
363#else
364 return nullptr;
365#endif
366 }
367
368 // Nothing else left to try.
369 return nullptr;
370}
This is a convenience class to specialize ConfigVariable as an integer type.
get_value
Returns the variable's value.
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.
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.