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