• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             if (!strcmp(gpu_option, "lavapipe")) {
239                 gpu_mode = "swiftshader_indirect";
240             } else {
241                 gpu_mode = gpu_option;
242             }
243         }
244     } else {
245         // Support "hw.gpu.mode=on" in config.ini
246         if (gpu_enabled && gpu_mode && (
247             !strcmp(gpu_mode, "on") ||
248             !strcmp(gpu_mode, "enable") ||
249             !strcmp(gpu_mode, "host"))) {
250             gpu_enabled = true;
251             gpu_mode = "host";
252             host_set_in_hwconfig = true;
253         }
254     }
255     sGpuOption = gpu_mode;
256 
257     if (gpu_mode &&
258         (!strcmp(gpu_mode, "guest") ||
259          !strcmp(gpu_mode, "off"))) {
260         gpu_enabled = false;
261     }
262 
263     if (!gpu_option && hasUiPreference) {
264         gpu_enabled = true;
265         gpu_mode = "auto";
266     }
267 
268     if (!gpu_enabled) {
269         config->enabled = false;
270         snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
271         snprintf(config->status, sizeof(config->status),
272                  "GPU emulation is disabled");
273         setCurrentRenderer(gpu_mode);
274         return true;
275     }
276 
277     if (gpu_mode && !strcmp("angle", gpu_mode)) {
278         gpu_mode = "angle_indirect";
279     }
280 
281     if (gpu_mode && !strcmp("swiftshader", gpu_mode)) {
282         gpu_mode = "swiftshader_indirect";
283     }
284 
285     if (!bitness) {
286         bitness = 64;
287     }
288 
289     config->bitness = bitness;
290     config->use_host_vulkan = use_host_vulkan;
291     resetBackendList(bitness);
292 
293     // Check that the GPU mode is a valid value. 'auto' means determine
294     // the best mode depending on the environment. Its purpose is to
295     // enable 'swiftshader' mode automatically when NX or Chrome Remote Desktop
296     // is detected.
297     if ((gpu_mode && !strcmp(gpu_mode, "auto")) || host_set_in_hwconfig) {
298         // The default will be 'host' unless:
299         // 1. NX or Chrome Remote Desktop is detected, or |no_window| is true.
300         // 2. The user's host GPU is on the blacklist.
301         std::string sessionType;
302         if (!has_auto_no_window && (no_window || (blacklisted && !hasUiPreference))) {
303             if (stringVectorContains(sBackendList->names(), "swiftshader")) {
304                 D("%s: Headless mode or blacklisted GPU driver, "
305                   "using Swiftshader backend\n",
306                   __FUNCTION__);
307                 gpu_mode = "swiftshader_indirect";
308             } else if (!has_guest_renderer) {
309                 D("%s: Headless (-no-window) mode (or blacklisted GPU driver)"
310                   " without Swiftshader, forcing '-gpu off'\n",
311                   __FUNCTION__);
312                 config->enabled = false;
313                 gpu_mode = "off";
314                 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
315                 snprintf(config->status, sizeof(config->status),
316                         "GPU emulation is disabled (-no-window without Swiftshader)");
317                 setCurrentRenderer(gpu_mode);
318                 return true;
319             } else {
320                 D("%s: Headless (-no-window) mode (or blacklisted GPU driver)"
321                   ", using guest GPU backend\n",
322                   __FUNCTION__);
323                 config->enabled = false;
324                 gpu_mode = "off";
325                 snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
326                 snprintf(config->status, sizeof(config->status),
327                         "GPU emulation is in the guest");
328                 gpu_mode = "guest";
329                 setCurrentRenderer(gpu_mode);
330                 return true;
331             }
332         } else {
333             switch (uiPreferredBackend) {
334                 case WINSYS_GLESBACKEND_PREFERENCE_ANGLE:
335                     gpu_mode = "angle_indirect";
336                     break;
337                 case WINSYS_GLESBACKEND_PREFERENCE_ANGLE9:
338                     gpu_mode = "angle_indirect";
339                     break;
340                 case WINSYS_GLESBACKEND_PREFERENCE_SWIFTSHADER:
341                     gpu_mode = "swiftshader_indirect";
342                     break;
343                 case WINSYS_GLESBACKEND_PREFERENCE_NATIVEGL:
344                     gpu_mode = "host";
345                     break;
346                 default:
347                     gpu_mode = "host";
348                     break;
349             }
350             D("%s: auto-selected %s based on conditions and UI preference %d\n",
351               __func__, gpu_mode, uiPreferredBackend);
352         }
353     }
354 
355     // 'host' is a special value corresponding to the default translation
356     // to desktop GL, 'guest' does not use host-side emulation,
357     // anything else must be checked against existing host-side backends.
358     if (!gpu_mode ||
359         (strcmp(gpu_mode, "host") != 0 && strcmp(gpu_mode, "guest") != 0)) {
360         const std::vector<std::string>& backends = sBackendList->names();
361         if (!gpu_mode || !stringVectorContains(backends, gpu_mode)) {
362             std::string error = StringFormat(
363                 "Invalid GPU mode '%s', use one of: host swiftshader_indirect. "
364                 "If you're already using one of those modes, "
365                 "the emulator installation may be corrupt. "
366                 "Please re-install the emulator.", gpu_mode);
367 
368             for (size_t n = 0; n < backends.size(); ++n) {
369                 error += " ";
370                 error += backends[n];
371             }
372 
373             D("%s: Error: [%s]\n", __func__, error.c_str());
374             fprintf(stderr, "%s: %s\n", __func__, error.c_str());
375 
376             config->enabled = false;
377             gpu_mode = "error";
378             snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
379             snprintf(config->status, sizeof(config->status), "%s",
380                      error.c_str());
381             setCurrentRenderer(gpu_mode);
382             return false;
383         }
384     }
385 
386     if (strcmp(gpu_mode, "guest")) {
387         config->enabled = true;
388     }
389 
390     snprintf(config->backend, sizeof(config->backend), "%s", gpu_mode);
391     snprintf(config->status, sizeof(config->status),
392              "GPU emulation enabled using '%s' mode", gpu_mode);
393     setCurrentRenderer(gpu_mode);
394     D("%s: %s\n", __func__, config->status);
395     return true;
396 }
397 
emuglConfig_setupEnv(const EmuglConfig * config)398 void emuglConfig_setupEnv(const EmuglConfig* config) {
399     if (config->use_host_vulkan) {
400         android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", "");
401     } else if (sCurrentRenderer == SELECTED_RENDERER_SWIFTSHADER_INDIRECT) {
402         // Use Swiftshader vk icd if using swiftshader_indirect
403         android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", "swiftshader");
404     }
405 
406     if (0 == strcmp(emuglConfig_get_user_gpu_option(), "lavapipe")) {
407         android::base::setEnvironmentVariable("ANDROID_EMU_VK_ICD", "lavapipe");
408     }
409 
410     if (!config->enabled) {
411         // There is no real GPU emulation. As a special case, define
412         // SDL_RENDER_DRIVER to 'software' to ensure that the
413         // software SDL renderer is being used. This allows one
414         // to run with '-gpu off' under NX and Chrome Remote Desktop
415         // properly.
416         android::base::setEnvironmentVariable("SDL_RENDER_DRIVER", "software");
417         return;
418     }
419 
420     // $EXEC_DIR/<lib>/ is already added to the library search path by default,
421     // since generic libraries are bundled there. We may need more though:
422     resetBackendList(config->bitness);
423     if (strcmp(config->backend, "host") != 0) {
424         // If the backend is not 'host', we also need to add the
425         // backend directory.
426         std::string dir = sBackendList->getLibDirPath(config->backend);
427         if (dir.size()) {
428             D("Adding to the library search path: %s\n", dir.c_str());
429             // fprintf(stderr, "%s: non-host backends not supported\n", __func__);
430             // abort();
431             // android::base::addLibrarySearchDir(dir);
432         }
433     }
434 
435     if (!strcmp(config->backend, "host")) {
436         // Nothing more to do for the 'host' backend.
437         return;
438     }
439 
440     if (!strcmp(config->backend, "angle_indirect")
441             || !strcmp(config->backend, "swiftshader_indirect")) {
442         android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1");
443         return;
444     }
445 
446     // For now, EmuGL selects its own translation libraries for
447     // EGL/GLES libraries, unless the following environment
448     // variables are defined:
449     //    ANDROID_EGL_LIB
450     //    ANDROID_GLESv1_LIB
451     //    ANDROID_GLESv2_LIB
452     //
453     // If a backend provides one of these libraries, use it.
454     std::string lib;
455     if (sBackendList->getBackendLibPath(
456             config->backend, EmuglBackendList::LIBRARY_EGL, &lib)) {
457         android::base::setEnvironmentVariable("ANDROID_EGL_LIB", lib);
458     }
459     if (sBackendList->getBackendLibPath(
460             config->backend, EmuglBackendList::LIBRARY_GLESv1, &lib)) {
461         android::base::setEnvironmentVariable("ANDROID_GLESv1_LIB", lib);
462     } else if (strcmp(config->backend, "mesa")) {
463         fprintf(stderr, "OpenGL backend '%s' without OpenGL ES 1.x library detected. "
464                         "Using GLESv2 only.\n",
465                         config->backend);
466         // A GLESv1 lib is optional---we can deal with a GLESv2 only
467         // backend by using CoreProfileEngine in the Translator.
468     }
469 
470     if (sBackendList->getBackendLibPath(
471             config->backend, EmuglBackendList::LIBRARY_GLESv2, &lib)) {
472         android::base::setEnvironmentVariable("ANDROID_GLESv2_LIB", lib);
473     }
474 
475     if (!strcmp(config->backend, "mesa")) {
476         fprintf(stderr, "WARNING: The Mesa software renderer is deprecated. "
477                         "Use Swiftshader (-gpu swiftshader) for software rendering.\n");
478         android::base::setEnvironmentVariable("ANDROID_GL_LIB", "mesa");
479         android::base::setEnvironmentVariable("ANDROID_GL_SOFTWARE_RENDERER", "1");
480     }
481 }
482