• 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             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