1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "host-common/opengl/emugl_config.h"
16
17 #include "aemu/base/StringFormat.h"
18 #include "aemu/base/system/System.h"
19 #include "host-common/globals.h"
20 #include "host-common/opengl/EmuglBackendList.h"
21 #include "host-common/opengl/gpuinfo.h"
22 #include "host-common/opengl/misc.h"
23
24 #include <string>
25
26 #include <assert.h>
27 #include <inttypes.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #define DEBUG 0
33
34 #if DEBUG
35 #define D(...) printf(__VA_ARGS__)
36 #else
37 // #define D(...) crashhandler_append_message_format(__VA_ARGS__)
38 #define D(...)
39 #endif
40
41 using android::base::StringFormat;
42 using android::opengl::EmuglBackendList;
43
44 static EmuglBackendList* sBackendList = NULL;
45
resetBackendList(int bitness)46 static void resetBackendList(int bitness) {
47 delete sBackendList;
48 std::vector<std::string> fixedBackendNames = {
49 "swiftshader_indirect",
50 "angle_indirect",
51 };
52 sBackendList = new EmuglBackendList(64, fixedBackendNames);
53 }
54
stringVectorContains(const std::vector<std::string> & list,const char * value)55 static bool stringVectorContains(const std::vector<std::string>& list,
56 const char* value) {
57 for (size_t n = 0; n < list.size(); ++n) {
58 if (!strcmp(list[n].c_str(), value)) {
59 return true;
60 }
61 }
62 return false;
63 }
64
isHostGpuBlacklisted()65 bool isHostGpuBlacklisted() {
66 return async_query_host_gpu_blacklisted();
67 }
68
69 // Get a description of host GPU properties.
70 // Need to free after use.
emuglConfig_get_host_gpu_props()71 emugl_host_gpu_prop_list emuglConfig_get_host_gpu_props() {
72 const GpuInfoList& gpulist = globalGpuInfoList();
73 emugl_host_gpu_prop_list res;
74 res.num_gpus = gpulist.infos.size();
75 res.props = new emugl_host_gpu_props[res.num_gpus];
76
77 const std::vector<GpuInfo>& infos = gpulist.infos;
78 for (int i = 0; i < res.num_gpus; i++) {
79 res.props[i].make = strdup(infos[i].make.c_str());
80 res.props[i].model = strdup(infos[i].model.c_str());
81 res.props[i].device_id = strdup(infos[i].device_id.c_str());
82 res.props[i].revision_id = strdup(infos[i].revision_id.c_str());
83 res.props[i].version = strdup(infos[i].version.c_str());
84 res.props[i].renderer = strdup(infos[i].renderer.c_str());
85 }
86 return res;
87 }
88
emuglConfig_get_renderer(const char * gpu_mode)89 SelectedRenderer emuglConfig_get_renderer(const char* gpu_mode) {
90 if (!gpu_mode) {
91 return SELECTED_RENDERER_UNKNOWN;
92 } else if (!strcmp(gpu_mode, "host") ||
93 !strcmp(gpu_mode, "on")) {
94 return SELECTED_RENDERER_HOST;
95 } else if (!strcmp(gpu_mode, "off")) {
96 return SELECTED_RENDERER_OFF;
97 } else if (!strcmp(gpu_mode, "guest")) {
98 return SELECTED_RENDERER_GUEST;
99 } else if (!strcmp(gpu_mode, "mesa")) {
100 return SELECTED_RENDERER_MESA;
101 } else if (!strcmp(gpu_mode, "swiftshader")) {
102 return SELECTED_RENDERER_SWIFTSHADER;
103 } else if (!strcmp(gpu_mode, "angle")) {
104 return SELECTED_RENDERER_ANGLE;
105 } else if (!strcmp(gpu_mode, "angle9")) {
106 return SELECTED_RENDERER_ANGLE9;
107 } else if (!strcmp(gpu_mode, "swiftshader_indirect")) {
108 return SELECTED_RENDERER_SWIFTSHADER_INDIRECT;
109 } else if (!strcmp(gpu_mode, "angle_indirect")) {
110 return SELECTED_RENDERER_ANGLE_INDIRECT;
111 } else if (!strcmp(gpu_mode, "angle9_indirect")) {
112 return SELECTED_RENDERER_ANGLE9_INDIRECT;
113 } else if (!strcmp(gpu_mode, "error")) {
114 return SELECTED_RENDERER_ERROR;
115 } else {
116 return SELECTED_RENDERER_UNKNOWN;
117 }
118 }
119
120 static SelectedRenderer sCurrentRenderer =
121 SELECTED_RENDERER_UNKNOWN;
122
emuglConfig_get_current_renderer()123 SelectedRenderer emuglConfig_get_current_renderer() {
124 return sCurrentRenderer;
125 }
126
127 static std::string sGpuOption;
128
emuglConfig_get_user_gpu_option()129 const char* emuglConfig_get_user_gpu_option() {
130 return sGpuOption.c_str();
131 }
132
emuglConfig_renderer_to_string(SelectedRenderer renderer)133 const char* emuglConfig_renderer_to_string(SelectedRenderer renderer) {
134 switch (renderer) {
135 case SELECTED_RENDERER_UNKNOWN:
136 return "(Unknown)";
137 case SELECTED_RENDERER_HOST:
138 return "Host";
139 case SELECTED_RENDERER_OFF:
140 return "Off";
141 case SELECTED_RENDERER_GUEST:
142 return "Guest";
143 case SELECTED_RENDERER_MESA:
144 return "Mesa";
145 case SELECTED_RENDERER_SWIFTSHADER:
146 return "Swiftshader";
147 case SELECTED_RENDERER_ANGLE:
148 return "Angle";
149 case SELECTED_RENDERER_ANGLE9:
150 return "Angle9";
151 case SELECTED_RENDERER_SWIFTSHADER_INDIRECT:
152 return "Swiftshader Indirect";
153 case SELECTED_RENDERER_ANGLE_INDIRECT:
154 return "Angle Indirect";
155 case SELECTED_RENDERER_ANGLE9_INDIRECT:
156 return "Angle9 Indirect";
157 case SELECTED_RENDERER_ERROR:
158 return "(Error)";
159 }
160 return "(Bad value)";
161 }
162
emuglConfig_current_renderer_supports_snapshot()163 bool emuglConfig_current_renderer_supports_snapshot() {
164 if (aemu_get_android_hw()->hw_arc) {
165 return sCurrentRenderer == SELECTED_RENDERER_OFF ||
166 sCurrentRenderer == SELECTED_RENDERER_GUEST;
167 }
168 return sCurrentRenderer == SELECTED_RENDERER_HOST ||
169 sCurrentRenderer == SELECTED_RENDERER_OFF ||
170 sCurrentRenderer == SELECTED_RENDERER_GUEST ||
171 sCurrentRenderer == SELECTED_RENDERER_ANGLE_INDIRECT ||
172 sCurrentRenderer == SELECTED_RENDERER_SWIFTSHADER_INDIRECT;
173 }
174
free_emugl_host_gpu_props(emugl_host_gpu_prop_list proplist)175 void free_emugl_host_gpu_props(emugl_host_gpu_prop_list proplist) {
176 for (int i = 0; i < proplist.num_gpus; i++) {
177 free(proplist.props[i].make);
178 free(proplist.props[i].model);
179 free(proplist.props[i].device_id);
180 free(proplist.props[i].revision_id);
181 free(proplist.props[i].version);
182 free(proplist.props[i].renderer);
183 }
184 delete [] proplist.props;
185 }
186
setCurrentRenderer(const char * gpuMode)187 static void setCurrentRenderer(const char* gpuMode) {
188 sCurrentRenderer = emuglConfig_get_renderer(gpuMode);
189 }
190
emuglConfig_init(EmuglConfig * config,bool gpu_enabled,const char * gpu_mode,const char * gpu_option,int bitness,bool no_window,bool blacklisted,bool has_guest_renderer,int uiPreferredBackend,bool use_host_vulkan)191 bool emuglConfig_init(EmuglConfig* config,
192 bool gpu_enabled,
193 const char* gpu_mode,
194 const char* gpu_option,
195 int bitness,
196 bool no_window,
197 bool blacklisted,
198 bool has_guest_renderer,
199 int uiPreferredBackend,
200 bool use_host_vulkan) {
201 D("%s: blacklisted=%d has_guest_renderer=%d, mode: %s, option: %s\n",
202 __FUNCTION__,
203 blacklisted,
204 has_guest_renderer,
205 gpu_mode, gpu_option);
206
207 // zero all fields first.
208 memset(config, 0, sizeof(*config));
209
210 bool host_set_in_hwconfig = false;
211 bool has_auto_no_window = false;
212
213 bool hasUiPreference = uiPreferredBackend != WINSYS_GLESBACKEND_PREFERENCE_AUTO;
214
215 // The value of '-gpu <mode>' overrides both the hardware properties
216 // and the UI setting, except if <mode> is 'auto'.
217 if (gpu_option) {
218 sGpuOption = gpu_option;
219 if (!strcmp(gpu_option, "on") || !strcmp(gpu_option, "enable")) {
220 gpu_enabled = true;
221 if (!gpu_mode || !strcmp(gpu_mode, "auto")) {
222 gpu_mode = "host";
223 }
224 } else if (!strcmp(gpu_option, "off") ||
225 !strcmp(gpu_option, "disable") ||
226 !strcmp(gpu_option, "guest")) {
227 gpu_mode = gpu_option;
228 gpu_enabled = false;
229 } else if (!strcmp(gpu_option, "auto")){
230 // Nothing to do, use gpu_mode set from
231 // hardware properties instead.
232 } else if (!strcmp(gpu_option, "auto-no-window")) {
233 // Nothing to do, use gpu_mode set from
234 // hardware properties instead.
235 has_auto_no_window = true;
236 } else {
237 gpu_enabled = true;
238 gpu_mode = gpu_option;
239 }
240 } else {
241 // Support "hw.gpu.mode=on" in config.ini
242 if (gpu_enabled && gpu_mode && (
243 !strcmp(gpu_mode, "on") ||
244 !strcmp(gpu_mode, "enable") ||
245 !strcmp(gpu_mode, "host"))) {
246 gpu_enabled = true;
247 gpu_mode = "host";
248 host_set_in_hwconfig = true;
249 }
250 }
251 sGpuOption = gpu_mode;
252
253 if (gpu_mode &&
254 (!strcmp(gpu_mode, "guest") ||
255 !strcmp(gpu_mode, "off"))) {
256 gpu_enabled = false;
257 }
258
259 if (!gpu_option && hasUiPreference) {
260 gpu_enabled = true;
261 gpu_mode = "auto";
262 }
263
264 if (!gpu_enabled) {
265 config->enabled = false;
266 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
267 snprintf(config->status, sizeof(config->status),
268 "GPU emulation is disabled");
269 setCurrentRenderer(gpu_mode);
270 return true;
271 }
272
273 if (gpu_mode && !strcmp("angle", gpu_mode)) {
274 gpu_mode = "angle_indirect";
275 }
276
277 if (gpu_mode && !strcmp("swiftshader", gpu_mode)) {
278 gpu_mode = "swiftshader_indirect";
279 }
280
281 if (!bitness) {
282 bitness = 64;
283 }
284
285 config->bitness = bitness;
286 config->use_host_vulkan = use_host_vulkan;
287 resetBackendList(bitness);
288
289 // Check that the GPU mode is a valid value. 'auto' means determine
290 // the best mode depending on the environment. Its purpose is to
291 // enable 'swiftshader' mode automatically when NX or Chrome Remote Desktop
292 // is detected.
293 if ((gpu_mode && !strcmp(gpu_mode, "auto")) || host_set_in_hwconfig) {
294 // The default will be 'host' unless:
295 // 1. NX or Chrome Remote Desktop is detected, or |no_window| is true.
296 // 2. The user's host GPU is on the blacklist.
297 std::string sessionType;
298 if (!has_auto_no_window && (no_window || (blacklisted && !hasUiPreference))) {
299 if (stringVectorContains(sBackendList->names(), "swiftshader")) {
300 D("%s: Headless mode or blacklisted GPU driver, "
301 "using Swiftshader backend\n",
302 __FUNCTION__);
303 gpu_mode = "swiftshader_indirect";
304 } else if (!has_guest_renderer) {
305 D("%s: Headless (-no-window) mode (or blacklisted GPU driver)"
306 " without Swiftshader, forcing '-gpu off'\n",
307 __FUNCTION__);
308 config->enabled = false;
309 gpu_mode = "off";
310 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
311 snprintf(config->status, sizeof(config->status),
312 "GPU emulation is disabled (-no-window without Swiftshader)");
313 setCurrentRenderer(gpu_mode);
314 return true;
315 } else {
316 D("%s: Headless (-no-window) mode (or blacklisted GPU driver)"
317 ", using guest GPU backend\n",
318 __FUNCTION__);
319 config->enabled = false;
320 gpu_mode = "off";
321 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
322 snprintf(config->status, sizeof(config->status),
323 "GPU emulation is in the guest");
324 gpu_mode = "guest";
325 setCurrentRenderer(gpu_mode);
326 return true;
327 }
328 } else {
329 switch (uiPreferredBackend) {
330 case WINSYS_GLESBACKEND_PREFERENCE_ANGLE:
331 gpu_mode = "angle_indirect";
332 break;
333 case WINSYS_GLESBACKEND_PREFERENCE_ANGLE9:
334 gpu_mode = "angle_indirect";
335 break;
336 case WINSYS_GLESBACKEND_PREFERENCE_SWIFTSHADER:
337 gpu_mode = "swiftshader_indirect";
338 break;
339 case WINSYS_GLESBACKEND_PREFERENCE_NATIVEGL:
340 gpu_mode = "host";
341 break;
342 default:
343 gpu_mode = "host";
344 break;
345 }
346 D("%s: auto-selected %s based on conditions and UI preference %d\n",
347 __func__, gpu_mode, uiPreferredBackend);
348 }
349 }
350
351 // 'host' is a special value corresponding to the default translation
352 // to desktop GL, 'guest' does not use host-side emulation,
353 // anything else must be checked against existing host-side backends.
354 if (!gpu_mode ||
355 (strcmp(gpu_mode, "host") != 0 && strcmp(gpu_mode, "guest") != 0)) {
356 const std::vector<std::string>& backends = sBackendList->names();
357 if (!gpu_mode || !stringVectorContains(backends, gpu_mode)) {
358 std::string error = StringFormat(
359 "Invalid GPU mode '%s', use one of: host swiftshader_indirect. "
360 "If you're already using one of those modes, "
361 "the emulator installation may be corrupt. "
362 "Please re-install the emulator.", gpu_mode);
363
364 for (size_t n = 0; n < backends.size(); ++n) {
365 error += " ";
366 error += backends[n];
367 }
368
369 D("%s: Error: [%s]\n", __func__, error.c_str());
370 fprintf(stderr, "%s: %s\n", __func__, error.c_str());
371
372 config->enabled = false;
373 gpu_mode = "error";
374 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
375 snprintf(config->status, sizeof(config->status), "%s",
376 error.c_str());
377 setCurrentRenderer(gpu_mode);
378 return false;
379 }
380 }
381
382 if (strcmp(gpu_mode, "guest")) {
383 config->enabled = true;
384 }
385
386 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
387 snprintf(config->status, sizeof(config->status),
388 "GPU emulation enabled using '%s' mode", gpu_mode);
389 setCurrentRenderer(gpu_mode);
390 D("%s: %s\n", __func__, config->status);
391 return true;
392 }
393
emuglConfig_setupEnv(const EmuglConfig * config)394 void emuglConfig_setupEnv(const EmuglConfig* config) {
395 if (config->use_host_vulkan) {
396 android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", "");
397 } else if (sCurrentRenderer == SELECTED_RENDERER_SWIFTSHADER_INDIRECT) {
398 // Use Swiftshader vk icd if using swiftshader_indirect
399 android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", "swiftshader");
400 }
401
402 if (!config->enabled) {
403 // There is no real GPU emulation. As a special case, define
404 // SDL_RENDER_DRIVER to 'software' to ensure that the
405 // software SDL renderer is being used. This allows one
406 // to run with '-gpu off' under NX and Chrome Remote Desktop
407 // properly.
408 android::base::setEnvironmentVariable("SDL_RENDER_DRIVER", "software");
409 return;
410 }
411
412 // $EXEC_DIR/<lib>/ is already added to the library search path by default,
413 // since generic libraries are bundled there. We may need more though:
414 resetBackendList(config->bitness);
415 if (strcmp(config->backend, "host") != 0) {
416 // If the backend is not 'host', we also need to add the
417 // backend directory.
418 std::string dir = sBackendList->getLibDirPath(config->backend);
419 if (dir.size()) {
420 D("Adding to the library search path: %s\n", dir.c_str());
421 // fprintf(stderr, "%s: non-host backends not supported\n", __func__);
422 // abort();
423 // android::base::addLibrarySearchDir(dir);
424 }
425 }
426
427 if (!strcmp(config->backend, "host")) {
428 // Nothing more to do for the 'host' backend.
429 return;
430 }
431
432 if (!strcmp(config->backend, "angle_indirect")
433 || !strcmp(config->backend, "swiftshader_indirect")) {
434 android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1");
435 return;
436 }
437
438 // For now, EmuGL selects its own translation libraries for
439 // EGL/GLES libraries, unless the following environment
440 // variables are defined:
441 // ANDROID_EGL_LIB
442 // ANDROID_GLESv1_LIB
443 // ANDROID_GLESv2_LIB
444 //
445 // If a backend provides one of these libraries, use it.
446 std::string lib;
447 if (sBackendList->getBackendLibPath(
448 config->backend, EmuglBackendList::LIBRARY_EGL, &lib)) {
449 android::base::setEnvironmentVariable("ANDROID_EGL_LIB", lib);
450 }
451 if (sBackendList->getBackendLibPath(
452 config->backend, EmuglBackendList::LIBRARY_GLESv1, &lib)) {
453 android::base::setEnvironmentVariable("ANDROID_GLESv1_LIB", lib);
454 } else if (strcmp(config->backend, "mesa")) {
455 fprintf(stderr, "OpenGL backend '%s' without OpenGL ES 1.x library detected. "
456 "Using GLESv2 only.\n",
457 config->backend);
458 // A GLESv1 lib is optional---we can deal with a GLESv2 only
459 // backend by using CoreProfileEngine in the Translator.
460 }
461
462 if (sBackendList->getBackendLibPath(
463 config->backend, EmuglBackendList::LIBRARY_GLESv2, &lib)) {
464 android::base::setEnvironmentVariable("ANDROID_GLESv2_LIB", lib);
465 }
466
467 if (!strcmp(config->backend, "mesa")) {
468 fprintf(stderr, "WARNING: The Mesa software renderer is deprecated. "
469 "Use Swiftshader (-gpu swiftshader) for software rendering.\n");
470 android::base::setEnvironmentVariable("ANDROID_GL_LIB", "mesa");
471 android::base::setEnvironmentVariable("ANDROID_GL_SOFTWARE_RENDERER", "1");
472 }
473 }
474