// Copyright 2020 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "android/opengl/emugl_config.h" #include "android/opengl/EmuglBackendList.h" #include "android/opengl/gpuinfo.h" #include "android/base/testing/TestSystem.h" #include "android/base/testing/TestTempDir.h" #include namespace android { namespace base { #if defined(_WIN32) # define LIB_NAME(x) x ".dll" #elif defined(__APPLE__) # define LIB_NAME(x) "lib" x ".dylib" #else # define LIB_NAME(x) "lib" x ".so" #endif static std::string makeLibSubPath(const char* name) { return StringFormat("%s/%s/%s", System::get()->getLauncherDirectory().c_str(), System::kLibSubDir, name); } static void makeLibSubDir(TestTempDir* dir, const char* name) { dir->makeSubDir(makeLibSubPath(name).c_str()); } static void makeLibSubFile(TestTempDir* dir, const char* name) { dir->makeSubFile(makeLibSubPath(name).c_str()); } TEST(EmuglConfig, init) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); makeLibSubDir(myDir, "gles_mesa"); makeLibSubFile(myDir, "gles_mesa/libGLES.so"); makeLibSubDir(myDir, "gles_vendor"); makeLibSubFile(myDir, "gles_vendor/" LIB_NAME("EGL")); makeLibSubFile(myDir, "gles_vendor/" LIB_NAME("GLESv2")); { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, "host", NULL, 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "host", NULL, 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("host", config.backend); EXPECT_STREQ("GPU emulation enabled using 'host' mode", config.status); } // Check that "host" mode is available with -no-window if explicitly // specified on command line. { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "host", "host", 0, true, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("host", config.backend); EXPECT_STREQ("GPU emulation enabled using 'host' mode", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "mesa", NULL, 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("mesa", config.backend); EXPECT_STREQ("GPU emulation enabled using 'mesa' mode", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "host", "off", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "host", "disable", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, "host", "on", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("host", config.backend); EXPECT_STREQ("GPU emulation enabled using 'host' mode", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, NULL, "on", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("host", config.backend); EXPECT_STREQ("GPU emulation enabled using 'host' mode", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, "mesa", "enable", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("mesa", config.backend); EXPECT_STREQ("GPU emulation enabled using 'mesa' mode", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, "vendor", "auto", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "host", "vendor", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("vendor", config.backend); EXPECT_STREQ("GPU emulation enabled using 'vendor' mode", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "guest", "auto", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, "guest", "auto", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "host", "guest", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); } } TEST(EmuglConfig, initFromUISetting) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); makeLibSubDir(myDir, "gles_mesa"); makeLibSubFile(myDir, "gles_mesa/libGLES.so"); makeLibSubDir(myDir, "gles_angle"); makeLibSubFile(myDir, "gles_angle/" LIB_NAME("EGL")); makeLibSubFile(myDir, "gles_angle/" LIB_NAME("GLESv2")); makeLibSubDir(myDir, "gles_angle9"); makeLibSubFile(myDir, "gles_angle9/" LIB_NAME("EGL")); makeLibSubFile(myDir, "gles_angle9/" LIB_NAME("GLESv2")); makeLibSubDir(myDir, "gles_swiftshader"); makeLibSubFile(myDir, "gles_swiftshader/" LIB_NAME("EGL")); makeLibSubFile(myDir, "gles_swiftshader/" LIB_NAME("GLESv2")); // If the gpu command line option is specified, the UI setting is overridden. for (int i = 0; i < 10; i++) { { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, "host", "on", 0, false, false, false, (enum WinsysPreferredGlesBackend)i, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("host", config.backend); EXPECT_STREQ("GPU emulation enabled using 'host' mode", config.status); } { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, "guest", "auto", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled", config.status); } } // If the UI setting is not "auto", and there is no gpu command line option, // then use the UI setting, regardless of the AVD config. for (int i = 1; i < 5; i++) { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, false, "host", NULL, 0, false, false, false, (enum WinsysPreferredGlesBackend)i, false)); EXPECT_TRUE(config.enabled); switch (i) { case 0: EXPECT_STREQ("host", config.backend); break; case 1: EXPECT_STREQ("angle_indirect", config.backend); break; case 2: EXPECT_STREQ("angle_indirect", config.backend); break; case 3: EXPECT_STREQ("swiftshader_indirect", config.backend); break; case 4: EXPECT_STREQ("host", config.backend); break; default: break; } } } TEST(EmuglConfig, initGLESv2Only) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); makeLibSubDir(myDir, "gles_angle"); #ifdef _WIN32 const char* kEglLibName = "libEGL.dll"; const char* kGLESv1LibName = "libGLES_CM.dll"; const char* kGLESv2LibName = "libGLESv2.dll"; #elif defined(__APPLE__) const char* kEglLibName = "libEGL.dylib"; const char* kGLESv1LibName = "libGLES_CM.dylib"; const char* kGLESv2LibName = "libGLESv2.dylib"; #else const char* kEglLibName = "libEGL.so"; const char* kGLESv1LibName = "libGLES_CM.so"; const char* kGLESv2LibName = "libGLESv2.so"; #endif std::string eglLibPath = StringFormat("gles_angle/%s", kEglLibName); std::string GLESv1LibPath = StringFormat("gles_angle/%s", kGLESv1LibName); std::string GLESv2LibPath = StringFormat("gles_angle/%s", kGLESv2LibName); makeLibSubFile(myDir, eglLibPath.c_str()); makeLibSubFile(myDir, GLESv2LibPath.c_str()); { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "angle", "auto", 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("angle_indirect", config.backend); EXPECT_STREQ("GPU emulation enabled using 'angle_indirect' mode", config.status); emuglConfig_setupEnv(&config); } } TEST(EmuglConfig, initNxWithSwiftshader) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); makeLibSubDir(myDir, "gles_swiftshader"); makeLibSubFile(myDir, "gles_swiftshader/libEGL.so"); makeLibSubFile(myDir, "gles_swiftshader/libGLES_CM.so"); makeLibSubFile(myDir, "gles_swiftshader/libGLESv2.so"); testSys.setRemoteSessionType("NX"); EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "auto", NULL, 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("swiftshader_indirect", config.backend); EXPECT_STREQ("GPU emulation enabled using 'swiftshader_indirect' mode", config.status); } TEST(EmuglConfig, initNxWithoutSwiftshader) { TestSystem testSys("foo", System::kProgramBitness); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); testSys.setRemoteSessionType("NX"); EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "auto", NULL, 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled under NX without Swiftshader", config.status); } TEST(EmuglConfig, initChromeRemoteDesktopWithSwiftshader) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); makeLibSubDir(myDir, "gles_swiftshader"); makeLibSubFile(myDir, "gles_swiftshader/libEGL.so"); makeLibSubFile(myDir, "gles_swiftshader/libGLES_CM.so"); makeLibSubFile(myDir, "gles_swiftshader/libGLESv2.so"); testSys.setRemoteSessionType("Chrome Remote Desktop"); EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "auto", NULL, 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("swiftshader_indirect", config.backend); EXPECT_STREQ("GPU emulation enabled using 'swiftshader_indirect' mode", config.status); } TEST(EmuglConfig, initChromeRemoteDesktopWithoutSwiftshader) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); testSys.setRemoteSessionType("Chrome Remote Desktop"); EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "auto", NULL, 0, false, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled under Chrome Remote Desktop without Swiftshader", config.status); } TEST(EmuglConfig, initNoWindowWithSwiftshader) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); makeLibSubDir(myDir, "gles_swiftshader"); makeLibSubFile(myDir, "gles_swiftshader/libEGL.so"); makeLibSubFile(myDir, "gles_swiftshader/libGLES_CM.so"); makeLibSubFile(myDir, "gles_swiftshader/libGLESv2.so"); EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "auto", NULL, 0, true, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_TRUE(config.enabled); EXPECT_STREQ("swiftshader_indirect", config.backend); EXPECT_STREQ("GPU emulation enabled using 'swiftshader_indirect' mode", config.status); } TEST(EmuglConfig, initWithSwiftshaderCheckVulkanEnvVar) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); makeLibSubDir(myDir, "gles_swiftshader"); makeLibSubFile(myDir, "gles_swiftshader/libEGL.so"); makeLibSubFile(myDir, "gles_swiftshader/libGLES_CM.so"); makeLibSubFile(myDir, "gles_swiftshader/libGLESv2.so"); // Do not force use host vulkan { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "auto", NULL, 0, true, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); emuglConfig_setupEnv(&config); EXPECT_STREQ("swiftshader", System::get()->envGet("ANDROID_EMU_VK_ICD").c_str()); } // Force use host vulkan { EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "auto", NULL, 0, true, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, true)); emuglConfig_setupEnv(&config); EXPECT_STREQ("", System::get()->envGet("ANDROID_EMU_VK_ICD").c_str()); } } TEST(EmuglConfig, initNoWindowWithoutSwiftshader) { TestSystem testSys("foo", System::kProgramBitness, "/"); TestTempDir* myDir = testSys.getTempRoot(); myDir->makeSubDir(System::get()->getLauncherDirectory().c_str()); makeLibSubDir(myDir, ""); EmuglConfig config; EXPECT_TRUE(emuglConfig_init( &config, true, "auto", NULL, 0, true, false, false, WINSYS_GLESBACKEND_PREFERENCE_AUTO, false)); EXPECT_FALSE(config.enabled); EXPECT_STREQ("GPU emulation is disabled (-no-window without Swiftshader)", config.status); } TEST(EmuglConfig, setupEnv) { } TEST(EmuglConfig, hostGpuProps) { TestSystem testSys("/usr", 32); testSys.setLiveUnixTime(true); GpuInfoList* gpulist = const_cast(&globalGpuInfoList()); gpulist->clear(); EXPECT_TRUE(gpulist->infos.size() == 0); gpulist->addGpu(); gpulist->currGpu().make = "TEST GPU0 MAKE"; gpulist->currGpu().model = "TEST GPU0 MODEL"; gpulist->currGpu().device_id = "TEST GPU0 DEVICEID"; gpulist->currGpu().revision_id = "TEST GPU0 REVISIONID"; gpulist->currGpu().version = "TEST GPU0 VERSION"; gpulist->currGpu().renderer = "TEST GPU0 RENDERER"; gpulist->addGpu(); gpulist->currGpu().make = "TEST GPU1 MAKE"; gpulist->currGpu().model = "TEST GPU1 MODEL"; gpulist->currGpu().device_id = "TEST GPU1 DEVICEID"; gpulist->currGpu().revision_id = "TEST GPU1 REVISIONID"; gpulist->currGpu().version = "TEST GPU1 VERSION"; gpulist->currGpu().renderer = "TEST GPU1 RENDERER"; gpulist->addGpu(); gpulist->currGpu().make = "TEST GPU2 MAKE"; gpulist->currGpu().model = "TEST GPU2 MODEL"; gpulist->currGpu().device_id = "TEST GPU2 DEVICEID"; gpulist->currGpu().revision_id = "TEST GPU2 REVISIONID"; gpulist->currGpu().version = "TEST GPU2 VERSION"; gpulist->currGpu().renderer = "TEST GPU2 RENDERER"; gpulist->addGpu(); gpulist->currGpu().make = "TEST GPU3 MAKE"; gpulist->currGpu().model = "TEST GPU3 MODEL"; gpulist->currGpu().device_id = "TEST GPU3 DEVICEID"; gpulist->currGpu().revision_id = "TEST GPU3 REVISIONID"; gpulist->currGpu().version = "TEST GPU3 VERSION"; gpulist->currGpu().renderer = "TEST GPU3 RENDERER"; emugl_host_gpu_prop_list gpu_props = emuglConfig_get_host_gpu_props(); EXPECT_TRUE(gpu_props.num_gpus == 4); EXPECT_STREQ("TEST GPU0 MAKE", gpu_props.props[0].make); EXPECT_STREQ("TEST GPU1 MAKE", gpu_props.props[1].make); EXPECT_STREQ("TEST GPU2 MAKE", gpu_props.props[2].make); EXPECT_STREQ("TEST GPU3 MAKE", gpu_props.props[3].make); EXPECT_STREQ("TEST GPU0 MODEL", gpu_props.props[0].model); EXPECT_STREQ("TEST GPU1 MODEL", gpu_props.props[1].model); EXPECT_STREQ("TEST GPU2 MODEL", gpu_props.props[2].model); EXPECT_STREQ("TEST GPU3 MODEL", gpu_props.props[3].model); EXPECT_STREQ("TEST GPU0 DEVICEID", gpu_props.props[0].device_id); EXPECT_STREQ("TEST GPU1 DEVICEID", gpu_props.props[1].device_id); EXPECT_STREQ("TEST GPU2 DEVICEID", gpu_props.props[2].device_id); EXPECT_STREQ("TEST GPU3 DEVICEID", gpu_props.props[3].device_id); EXPECT_STREQ("TEST GPU0 REVISIONID", gpu_props.props[0].revision_id); EXPECT_STREQ("TEST GPU1 REVISIONID", gpu_props.props[1].revision_id); EXPECT_STREQ("TEST GPU2 REVISIONID", gpu_props.props[2].revision_id); EXPECT_STREQ("TEST GPU3 REVISIONID", gpu_props.props[3].revision_id); EXPECT_STREQ("TEST GPU0 VERSION", gpu_props.props[0].version); EXPECT_STREQ("TEST GPU1 VERSION", gpu_props.props[1].version); EXPECT_STREQ("TEST GPU2 VERSION", gpu_props.props[2].version); EXPECT_STREQ("TEST GPU3 VERSION", gpu_props.props[3].version); EXPECT_STREQ("TEST GPU0 RENDERER", gpu_props.props[0].renderer); EXPECT_STREQ("TEST GPU1 RENDERER", gpu_props.props[1].renderer); EXPECT_STREQ("TEST GPU2 RENDERER", gpu_props.props[2].renderer); EXPECT_STREQ("TEST GPU3 RENDERER", gpu_props.props[3].renderer); free_emugl_host_gpu_props(gpu_props); } TEST(EmuglConfig, hostGpuProps_empty) { TestSystem testSys("/usr", 32); testSys.setLiveUnixTime(true); GpuInfoList* gpulist = const_cast(&globalGpuInfoList()); gpulist->clear(); EXPECT_TRUE(gpulist->infos.size() == 0); emugl_host_gpu_prop_list gpu_props = emuglConfig_get_host_gpu_props(); EXPECT_TRUE(gpu_props.num_gpus == 0); free_emugl_host_gpu_props(gpu_props); } } // namespace base } // namespace android