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 "emugl_config.h"
16 #include "gpuinfo.h"
17
18 #include "base/StringFormat.h"
19 #include "base/System.h"
20 #include "../globals.h"
21 #include "../misc.h"
22 #include "EmuglBackendList.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
emuglConfig_renderer_to_string(SelectedRenderer renderer)127 const char* emuglConfig_renderer_to_string(SelectedRenderer renderer) {
128 switch (renderer) {
129 case SELECTED_RENDERER_UNKNOWN:
130 return "(Unknown)";
131 case SELECTED_RENDERER_HOST:
132 return "Host";
133 case SELECTED_RENDERER_OFF:
134 return "Off";
135 case SELECTED_RENDERER_GUEST:
136 return "Guest";
137 case SELECTED_RENDERER_MESA:
138 return "Mesa";
139 case SELECTED_RENDERER_SWIFTSHADER:
140 return "Swiftshader";
141 case SELECTED_RENDERER_ANGLE:
142 return "Angle";
143 case SELECTED_RENDERER_ANGLE9:
144 return "Angle9";
145 case SELECTED_RENDERER_SWIFTSHADER_INDIRECT:
146 return "Swiftshader Indirect";
147 case SELECTED_RENDERER_ANGLE_INDIRECT:
148 return "Angle Indirect";
149 case SELECTED_RENDERER_ANGLE9_INDIRECT:
150 return "Angle9 Indirect";
151 case SELECTED_RENDERER_ERROR:
152 return "(Error)";
153 }
154 return "(Bad value)";
155 }
156
emuglConfig_current_renderer_supports_snapshot()157 bool emuglConfig_current_renderer_supports_snapshot() {
158 if (android_hw->hw_arc) {
159 return sCurrentRenderer == SELECTED_RENDERER_OFF ||
160 sCurrentRenderer == SELECTED_RENDERER_GUEST;
161 }
162 return sCurrentRenderer == SELECTED_RENDERER_HOST ||
163 sCurrentRenderer == SELECTED_RENDERER_OFF ||
164 sCurrentRenderer == SELECTED_RENDERER_GUEST ||
165 sCurrentRenderer == SELECTED_RENDERER_ANGLE_INDIRECT ||
166 sCurrentRenderer == SELECTED_RENDERER_SWIFTSHADER_INDIRECT;
167 }
168
free_emugl_host_gpu_props(emugl_host_gpu_prop_list proplist)169 void free_emugl_host_gpu_props(emugl_host_gpu_prop_list proplist) {
170 for (int i = 0; i < proplist.num_gpus; i++) {
171 free(proplist.props[i].make);
172 free(proplist.props[i].model);
173 free(proplist.props[i].device_id);
174 free(proplist.props[i].revision_id);
175 free(proplist.props[i].version);
176 free(proplist.props[i].renderer);
177 }
178 delete [] proplist.props;
179 }
180
setCurrentRenderer(const char * gpuMode)181 static void setCurrentRenderer(const char* gpuMode) {
182 sCurrentRenderer = emuglConfig_get_renderer(gpuMode);
183 }
184
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)185 bool emuglConfig_init(EmuglConfig* config,
186 bool gpu_enabled,
187 const char* gpu_mode,
188 const char* gpu_option,
189 int bitness,
190 bool no_window,
191 bool blacklisted,
192 bool has_guest_renderer,
193 int uiPreferredBackend,
194 bool use_host_vulkan) {
195 D("%s: blacklisted=%d has_guest_renderer=%d, mode: %s, option: %s\n",
196 __FUNCTION__,
197 blacklisted,
198 has_guest_renderer,
199 gpu_mode, gpu_option);
200
201 // zero all fields first.
202 memset(config, 0, sizeof(*config));
203
204 bool host_set_in_hwconfig = false;
205 bool has_auto_no_window = false;
206
207 bool hasUiPreference = uiPreferredBackend != WINSYS_GLESBACKEND_PREFERENCE_AUTO;
208
209 // The value of '-gpu <mode>' overrides both the hardware properties
210 // and the UI setting, except if <mode> is 'auto'.
211 if (gpu_option) {
212 if (!strcmp(gpu_option, "on") || !strcmp(gpu_option, "enable")) {
213 gpu_enabled = true;
214 if (!gpu_mode || !strcmp(gpu_mode, "auto")) {
215 gpu_mode = "host";
216 }
217 } else if (!strcmp(gpu_option, "off") ||
218 !strcmp(gpu_option, "disable") ||
219 !strcmp(gpu_option, "guest")) {
220 gpu_mode = gpu_option;
221 gpu_enabled = false;
222 } else if (!strcmp(gpu_option, "auto")){
223 // Nothing to do, use gpu_mode set from
224 // hardware properties instead.
225 } else if (!strcmp(gpu_option, "auto-no-window")) {
226 // Nothing to do, use gpu_mode set from
227 // hardware properties instead.
228 has_auto_no_window = true;
229 } else {
230 gpu_enabled = true;
231 gpu_mode = gpu_option;
232 }
233 } else {
234 // Support "hw.gpu.mode=on" in config.ini
235 if (gpu_enabled && gpu_mode && (
236 !strcmp(gpu_mode, "on") ||
237 !strcmp(gpu_mode, "enable") ||
238 !strcmp(gpu_mode, "host"))) {
239 gpu_enabled = true;
240 gpu_mode = "host";
241 host_set_in_hwconfig = true;
242 }
243 }
244
245 if (gpu_mode &&
246 (!strcmp(gpu_mode, "guest") ||
247 !strcmp(gpu_mode, "off"))) {
248 gpu_enabled = false;
249 }
250
251 if (!gpu_option && hasUiPreference) {
252 gpu_enabled = true;
253 gpu_mode = "auto";
254 }
255
256 if (!gpu_enabled) {
257 config->enabled = false;
258 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
259 snprintf(config->status, sizeof(config->status),
260 "GPU emulation is disabled");
261 setCurrentRenderer(gpu_mode);
262 return true;
263 }
264
265 if (!strcmp("angle", gpu_mode)) {
266 gpu_mode = "angle_indirect";
267 }
268
269 if (!strcmp("swiftshader", gpu_mode)) {
270 gpu_mode = "swiftshader_indirect";
271 }
272
273 if (!bitness) {
274 bitness = 64;
275 }
276
277 config->bitness = bitness;
278 config->use_host_vulkan = use_host_vulkan;
279 resetBackendList(bitness);
280
281 // Check that the GPU mode is a valid value. 'auto' means determine
282 // the best mode depending on the environment. Its purpose is to
283 // enable 'swiftshader' mode automatically when NX or Chrome Remote Desktop
284 // is detected.
285 if (!strcmp(gpu_mode, "auto") || host_set_in_hwconfig) {
286 // The default will be 'host' unless:
287 // 1. NX or Chrome Remote Desktop is detected, or |no_window| is true.
288 // 2. The user's host GPU is on the blacklist.
289 std::string sessionType;
290 if (!has_auto_no_window && (no_window || (blacklisted && !hasUiPreference))) {
291 if (stringVectorContains(sBackendList->names(), "swiftshader")) {
292 D("%s: Headless mode or blacklisted GPU driver, "
293 "using Swiftshader backend\n",
294 __FUNCTION__);
295 gpu_mode = "swiftshader_indirect";
296 } else if (!has_guest_renderer) {
297 D("%s: Headless (-no-window) mode (or blacklisted GPU driver)"
298 " without Swiftshader, forcing '-gpu off'\n",
299 __FUNCTION__);
300 config->enabled = false;
301 gpu_mode = "off";
302 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
303 snprintf(config->status, sizeof(config->status),
304 "GPU emulation is disabled (-no-window without Swiftshader)");
305 setCurrentRenderer(gpu_mode);
306 return true;
307 } else {
308 D("%s: Headless (-no-window) mode (or blacklisted GPU driver)"
309 ", using guest GPU backend\n",
310 __FUNCTION__);
311 config->enabled = false;
312 gpu_mode = "off";
313 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
314 snprintf(config->status, sizeof(config->status),
315 "GPU emulation is in the guest");
316 gpu_mode = "guest";
317 setCurrentRenderer(gpu_mode);
318 return true;
319 }
320 } else {
321 switch (uiPreferredBackend) {
322 case WINSYS_GLESBACKEND_PREFERENCE_ANGLE:
323 gpu_mode = "angle_indirect";
324 break;
325 case WINSYS_GLESBACKEND_PREFERENCE_ANGLE9:
326 gpu_mode = "angle_indirect";
327 break;
328 case WINSYS_GLESBACKEND_PREFERENCE_SWIFTSHADER:
329 gpu_mode = "swiftshader_indirect";
330 break;
331 case WINSYS_GLESBACKEND_PREFERENCE_NATIVEGL:
332 gpu_mode = "host";
333 break;
334 default:
335 gpu_mode = "host";
336 break;
337 }
338 D("%s: auto-selected %s based on conditions and UI preference %d\n",
339 __func__, gpu_mode, uiPreferredBackend);
340 }
341 }
342
343 // 'host' is a special value corresponding to the default translation
344 // to desktop GL, 'guest' does not use host-side emulation,
345 // anything else must be checked against existing host-side backends.
346 if (strcmp(gpu_mode, "host") != 0 && strcmp(gpu_mode, "guest") != 0) {
347 const std::vector<std::string>& backends = sBackendList->names();
348 if (!stringVectorContains(backends, gpu_mode)) {
349 std::string error = StringFormat(
350 "Invalid GPU mode '%s', use one of: host swiftshader_indirect. "
351 "If you're already using one of those modes, "
352 "the emulator installation may be corrupt. "
353 "Please re-install the emulator.", gpu_mode);
354
355 for (size_t n = 0; n < backends.size(); ++n) {
356 error += " ";
357 error += backends[n];
358 }
359
360 D("%s: Error: [%s]\n", __func__, error.c_str());
361 fprintf(stderr, "%s: %s\n", __func__, error.c_str());
362
363 config->enabled = false;
364 gpu_mode = "error";
365 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
366 snprintf(config->status, sizeof(config->status), "%s",
367 error.c_str());
368 setCurrentRenderer(gpu_mode);
369 return false;
370 }
371 }
372
373 if (strcmp(gpu_mode, "guest")) {
374 config->enabled = true;
375 }
376
377 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
378 snprintf(config->status, sizeof(config->status),
379 "GPU emulation enabled using '%s' mode", gpu_mode);
380 setCurrentRenderer(gpu_mode);
381 D("%s: %s\n", __func__, config->status);
382 return true;
383 }
384
emuglConfig_setupEnv(const EmuglConfig * config)385 void emuglConfig_setupEnv(const EmuglConfig* config) {
386 if (config->use_host_vulkan) {
387 android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", "");
388 } else if (sCurrentRenderer == SELECTED_RENDERER_SWIFTSHADER_INDIRECT) {
389 // Use Swiftshader vk icd if using swiftshader_indirect
390 android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", "swiftshader");
391 }
392
393 if (!config->enabled) {
394 // There is no real GPU emulation. As a special case, define
395 // SDL_RENDER_DRIVER to 'software' to ensure that the
396 // software SDL renderer is being used. This allows one
397 // to run with '-gpu off' under NX and Chrome Remote Desktop
398 // properly.
399 android::base::setEnvironmentVariable("SDL_RENDER_DRIVER", "software");
400 return;
401 }
402
403 // $EXEC_DIR/<lib>/ is already added to the library search path by default,
404 // since generic libraries are bundled there. We may need more though:
405 resetBackendList(config->bitness);
406 if (strcmp(config->backend, "host") != 0) {
407 // If the backend is not 'host', we also need to add the
408 // backend directory.
409 std::string dir = sBackendList->getLibDirPath(config->backend);
410 if (dir.size()) {
411 D("Adding to the library search path: %s\n", dir.c_str());
412 // fprintf(stderr, "%s: non-host backends not supported\n", __func__);
413 // abort();
414 // android::base::addLibrarySearchDir(dir);
415 }
416 }
417
418 if (!strcmp(config->backend, "host")) {
419 // Nothing more to do for the 'host' backend.
420 return;
421 }
422
423 if (!strcmp(config->backend, "angle_indirect")
424 || !strcmp(config->backend, "swiftshader_indirect")) {
425 android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1");
426 return;
427 }
428
429 // For now, EmuGL selects its own translation libraries for
430 // EGL/GLES libraries, unless the following environment
431 // variables are defined:
432 // ANDROID_EGL_LIB
433 // ANDROID_GLESv1_LIB
434 // ANDROID_GLESv2_LIB
435 //
436 // If a backend provides one of these libraries, use it.
437 std::string lib;
438 if (sBackendList->getBackendLibPath(
439 config->backend, EmuglBackendList::LIBRARY_EGL, &lib)) {
440 android::base::setEnvironmentVariable("ANDROID_EGL_LIB", lib);
441 }
442 if (sBackendList->getBackendLibPath(
443 config->backend, EmuglBackendList::LIBRARY_GLESv1, &lib)) {
444 android::base::setEnvironmentVariable("ANDROID_GLESv1_LIB", lib);
445 } else if (strcmp(config->backend, "mesa")) {
446 fprintf(stderr, "OpenGL backend '%s' without OpenGL ES 1.x library detected. "
447 "Using GLESv2 only.\n",
448 config->backend);
449 // A GLESv1 lib is optional---we can deal with a GLESv2 only
450 // backend by using CoreProfileEngine in the Translator.
451 }
452
453 if (sBackendList->getBackendLibPath(
454 config->backend, EmuglBackendList::LIBRARY_GLESv2, &lib)) {
455 android::base::setEnvironmentVariable("ANDROID_GLESv2_LIB", lib);
456 }
457
458 if (!strcmp(config->backend, "mesa")) {
459 fprintf(stderr, "WARNING: The Mesa software renderer is deprecated. "
460 "Use Swiftshader (-gpu swiftshader) for software rendering.\n");
461 android::base::setEnvironmentVariable("ANDROID_GL_LIB", "mesa");
462 android::base::setEnvironmentVariable("ANDROID_GL_SOFTWARE_RENDERER", "1");
463 }
464 }
465