Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/linuxbsd/wayland/detect_prime_egl.cpp
10278 views
1
/**************************************************************************/
2
/* detect_prime_egl.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#ifdef GLES3_ENABLED
32
#ifdef EGL_ENABLED
33
34
#include "detect_prime_egl.h"
35
36
#include "core/string/print_string.h"
37
#include "core/string/ustring.h"
38
39
#include <sys/types.h>
40
#include <sys/wait.h>
41
#include <unistd.h>
42
#include <cstdlib>
43
44
// To prevent shadowing warnings.
45
#undef glGetString
46
47
// Runs inside a child. Exiting will not quit the engine.
48
void DetectPrimeEGL::create_context(EGLenum p_platform_enum) {
49
#if defined(GLAD_ENABLED)
50
if (!gladLoaderLoadEGL(nullptr)) {
51
print_verbose("Unable to load EGL, GPU detection skipped.");
52
quick_exit(1);
53
}
54
#endif
55
56
EGLDisplay egl_display = EGL_NO_DISPLAY;
57
58
if (GLAD_EGL_VERSION_1_5) {
59
egl_display = eglGetPlatformDisplay(p_platform_enum, nullptr, nullptr);
60
} else if (GLAD_EGL_EXT_platform_base) {
61
#ifdef EGL_EXT_platform_base
62
egl_display = eglGetPlatformDisplayEXT(p_platform_enum, nullptr, nullptr);
63
#endif
64
} else {
65
egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
66
}
67
68
EGLConfig egl_config;
69
EGLContext egl_context = EGL_NO_CONTEXT;
70
71
eglInitialize(egl_display, nullptr, nullptr);
72
73
#if defined(GLAD_ENABLED)
74
if (!gladLoaderLoadEGL(egl_display)) {
75
print_verbose("Unable to load EGL, GPU detection skipped.");
76
quick_exit(1);
77
}
78
#endif
79
80
eglBindAPI(EGL_OPENGL_API);
81
82
EGLint attribs[] = {
83
EGL_RED_SIZE,
84
1,
85
EGL_BLUE_SIZE,
86
1,
87
EGL_GREEN_SIZE,
88
1,
89
EGL_DEPTH_SIZE,
90
24,
91
EGL_NONE,
92
};
93
94
EGLint config_count = 0;
95
eglChooseConfig(egl_display, attribs, &egl_config, 1, &config_count);
96
97
EGLint context_attribs[] = {
98
EGL_CONTEXT_MAJOR_VERSION, 3,
99
EGL_CONTEXT_MINOR_VERSION, 3,
100
EGL_NONE
101
};
102
103
egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attribs);
104
if (egl_context == EGL_NO_CONTEXT) {
105
print_verbose("Unable to create an EGL context, GPU detection skipped.");
106
quick_exit(1);
107
}
108
109
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context);
110
}
111
112
int DetectPrimeEGL::detect_prime(EGLenum p_platform_enum) {
113
pid_t p;
114
int priorities[4] = {};
115
String vendors[4];
116
String renderers[4];
117
118
for (int i = 0; i < 4; ++i) {
119
vendors[i] = "Unknown";
120
renderers[i] = "Unknown";
121
}
122
123
for (int i = 0; i < 4; ++i) {
124
int fdset[2];
125
126
if (pipe(fdset) == -1) {
127
print_verbose("Failed to pipe(), using default GPU");
128
return 0;
129
}
130
131
// Fork so the driver initialization can crash without taking down the engine.
132
p = fork();
133
134
if (p > 0) {
135
// Main thread
136
137
int stat_loc = 0;
138
char string[201];
139
string[200] = '\0';
140
141
close(fdset[1]);
142
143
waitpid(p, &stat_loc, 0);
144
145
if (!stat_loc) {
146
// No need to do anything complicated here. Anything less than
147
// PIPE_BUF will be delivered in one read() call.
148
// Leave it 'Unknown' otherwise.
149
if (read(fdset[0], string, sizeof(string) - 1) > 0) {
150
vendors[i] = string;
151
renderers[i] = string + strlen(string) + 1;
152
}
153
}
154
155
close(fdset[0]);
156
} else {
157
// In child, exit() here will not quit the engine.
158
159
// Prevent false leak reports as we will not be properly
160
// cleaning up these processes, and fork() makes a copy
161
// of all globals.
162
CoreGlobals::leak_reporting_enabled = false;
163
164
char string[201];
165
166
close(fdset[0]);
167
168
setenv("DRI_PRIME", itos(i).utf8().ptr(), 1);
169
170
create_context(p_platform_enum);
171
172
PFNGLGETSTRINGPROC glGetString = (PFNGLGETSTRINGPROC)eglGetProcAddress("glGetString");
173
const char *vendor = (const char *)glGetString(GL_VENDOR);
174
const char *renderer = (const char *)glGetString(GL_RENDERER);
175
176
unsigned int vendor_len = strlen(vendor) + 1;
177
unsigned int renderer_len = strlen(renderer) + 1;
178
179
if (vendor_len + renderer_len >= sizeof(string)) {
180
renderer_len = 200 - vendor_len;
181
}
182
183
memcpy(&string, vendor, vendor_len);
184
memcpy(&string[vendor_len], renderer, renderer_len);
185
186
if (write(fdset[1], string, vendor_len + renderer_len) == -1) {
187
print_verbose("Couldn't write vendor/renderer string.");
188
}
189
close(fdset[1]);
190
191
// The function quick_exit() is used because exit() will call destructors on static objects copied by fork().
192
// These objects will be freed anyway when the process finishes execution.
193
quick_exit(0);
194
}
195
}
196
197
int preferred = 0;
198
int priority = 0;
199
200
if (vendors[0] == vendors[1]) {
201
print_verbose("Only one GPU found, using default.");
202
return 0;
203
}
204
205
for (int i = 3; i >= 0; --i) {
206
const Vendor *v = vendor_map;
207
while (v->glxvendor) {
208
if (v->glxvendor == vendors[i]) {
209
priorities[i] = v->priority;
210
211
if (v->priority >= priority) {
212
priority = v->priority;
213
preferred = i;
214
}
215
}
216
++v;
217
}
218
}
219
220
print_verbose("Found renderers:");
221
for (int i = 0; i < 4; ++i) {
222
print_verbose("Renderer " + itos(i) + ": " + renderers[i] + " with priority: " + itos(priorities[i]));
223
}
224
225
print_verbose("Using renderer: " + renderers[preferred]);
226
return preferred;
227
}
228
229
#endif // EGL_ENABLED
230
#endif // GLES3_ENABLED
231
232