• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // vulkan_icd.cpp : Helper for creating vulkan instances & selecting physical device.
8 
9 #include "common/vulkan/vulkan_icd.h"
10 
11 #include <functional>
12 #include <vector>
13 
14 #include "common/bitset_utils.h"
15 #include "common/debug.h"
16 #include "common/system_utils.h"
17 
18 namespace angle
19 {
20 
21 namespace vk
22 {
23 
24 namespace
25 {
26 
27 // This function is unused on Android/Fuschia/GGP
28 #if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA) && \
29     !defined(ANGLE_PLATFORM_GGP)
WrapICDEnvironment(const char * icdEnvironment)30 const std::string WrapICDEnvironment(const char *icdEnvironment)
31 {
32 #    if defined(ANGLE_PLATFORM_APPLE)
33     // On MacOS the libraries are bundled into the application directory
34     std::string ret = angle::GetHelperExecutableDir() + icdEnvironment;
35     return ret;
36 #    endif  // defined(ANGLE_PLATFORM_APPLE)
37     return icdEnvironment;
38 }
39 
40 constexpr char kLoaderLayersPathEnv[] = "VK_LAYER_PATH";
41 #endif
42 
43 constexpr char kLoaderICDFilenamesEnv[]   = "VK_ICD_FILENAMES";
44 constexpr char kANGLEPreferredDeviceEnv[] = "ANGLE_PREFERRED_DEVICE";
45 
46 constexpr uint32_t kMockVendorID = 0xba5eba11;
47 constexpr uint32_t kMockDeviceID = 0xf005ba11;
48 constexpr char kMockDeviceName[] = "Vulkan Mock Device";
49 
50 constexpr uint32_t kGoogleVendorID      = 0x1AE0;
51 constexpr uint32_t kSwiftShaderDeviceID = 0xC0DE;
52 constexpr char kSwiftShaderDeviceName[] = "SwiftShader Device";
53 
54 using ICDFilterFunc = std::function<bool(const VkPhysicalDeviceProperties &)>;
55 
GetFilterForICD(vk::ICD preferredICD)56 ICDFilterFunc GetFilterForICD(vk::ICD preferredICD)
57 {
58     switch (preferredICD)
59     {
60         case vk::ICD::Mock:
61             return [](const VkPhysicalDeviceProperties &deviceProperties) {
62                 return ((deviceProperties.vendorID == kMockVendorID) &&
63                         (deviceProperties.deviceID == kMockDeviceID) &&
64                         (strcmp(deviceProperties.deviceName, kMockDeviceName) == 0));
65             };
66         case vk::ICD::SwiftShader:
67             return [](const VkPhysicalDeviceProperties &deviceProperties) {
68                 return ((deviceProperties.vendorID == kGoogleVendorID) &&
69                         (deviceProperties.deviceID == kSwiftShaderDeviceID) &&
70                         (strncmp(deviceProperties.deviceName, kSwiftShaderDeviceName,
71                                  strlen(kSwiftShaderDeviceName)) == 0));
72             };
73         default:
74             const std::string anglePreferredDevice =
75                 angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
76             return [anglePreferredDevice](const VkPhysicalDeviceProperties &deviceProperties) {
77                 return (anglePreferredDevice.empty() ||
78                         anglePreferredDevice == deviceProperties.deviceName);
79             };
80     }
81 }
82 
83 }  // namespace
84 
85 // If we're loading the validation layers, we could be running from any random directory.
86 // Change to the executable directory so we can find the layers, then change back to the
87 // previous directory to be safe we don't disrupt the application.
ScopedVkLoaderEnvironment(bool enableValidationLayers,vk::ICD icd)88 ScopedVkLoaderEnvironment::ScopedVkLoaderEnvironment(bool enableValidationLayers, vk::ICD icd)
89     : mEnableValidationLayers(enableValidationLayers),
90       mICD(icd),
91       mChangedCWD(false),
92       mChangedICDEnv(false)
93 {
94 // Changing CWD and setting environment variables makes no sense on Android,
95 // since this code is a part of Java application there.
96 // Android Vulkan loader doesn't need this either.
97 #if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA) && \
98     !defined(ANGLE_PLATFORM_GGP)
99     if (icd == vk::ICD::Mock)
100     {
101         if (!setICDEnvironment(WrapICDEnvironment(ANGLE_VK_MOCK_ICD_JSON).c_str()))
102         {
103             ERR() << "Error setting environment for Mock/Null Driver.";
104         }
105     }
106 #    if defined(ANGLE_VK_SWIFTSHADER_ICD_JSON)
107     else if (icd == vk::ICD::SwiftShader)
108     {
109         if (!setICDEnvironment(WrapICDEnvironment(ANGLE_VK_SWIFTSHADER_ICD_JSON).c_str()))
110         {
111             ERR() << "Error setting environment for SwiftShader.";
112         }
113     }
114 #    endif  // defined(ANGLE_VK_SWIFTSHADER_ICD_JSON)
115     if (mEnableValidationLayers || icd != vk::ICD::Default)
116     {
117         const auto &cwd = angle::GetCWD();
118         if (!cwd.valid())
119         {
120             ERR() << "Error getting CWD for Vulkan layers init.";
121             mEnableValidationLayers = false;
122             mICD                    = vk::ICD::Default;
123         }
124         else
125         {
126             mPreviousCWD       = cwd.value();
127             std::string exeDir = angle::GetExecutableDirectory();
128             mChangedCWD        = angle::SetCWD(exeDir.c_str());
129             if (!mChangedCWD)
130             {
131                 ERR() << "Error setting CWD for Vulkan layers init.";
132                 mEnableValidationLayers = false;
133                 mICD                    = vk::ICD::Default;
134             }
135         }
136     }
137 
138     // Override environment variable to use the ANGLE layers.
139     if (mEnableValidationLayers)
140     {
141         if (!angle::PrependPathToEnvironmentVar(kLoaderLayersPathEnv, ANGLE_VK_LAYERS_DIR))
142         {
143             ERR() << "Error setting environment for Vulkan layers init.";
144             mEnableValidationLayers = false;
145         }
146     }
147 #endif  // !defined(ANGLE_PLATFORM_ANDROID)
148 }
149 
~ScopedVkLoaderEnvironment()150 ScopedVkLoaderEnvironment::~ScopedVkLoaderEnvironment()
151 {
152     if (mChangedCWD)
153     {
154 #if !defined(ANGLE_PLATFORM_ANDROID)
155         ASSERT(mPreviousCWD.valid());
156         angle::SetCWD(mPreviousCWD.value().c_str());
157 #endif  // !defined(ANGLE_PLATFORM_ANDROID)
158     }
159     if (mChangedICDEnv)
160     {
161         if (mPreviousICDEnv.value().empty())
162         {
163             angle::UnsetEnvironmentVar(kLoaderICDFilenamesEnv);
164         }
165         else
166         {
167             angle::SetEnvironmentVar(kLoaderICDFilenamesEnv, mPreviousICDEnv.value().c_str());
168         }
169     }
170 }
171 
setICDEnvironment(const char * icd)172 bool ScopedVkLoaderEnvironment::setICDEnvironment(const char *icd)
173 {
174     // Override environment variable to use built Mock ICD
175     // ANGLE_VK_ICD_JSON gets set to the built mock ICD in BUILD.gn
176     mPreviousICDEnv = angle::GetEnvironmentVar(kLoaderICDFilenamesEnv);
177     mChangedICDEnv  = angle::SetEnvironmentVar(kLoaderICDFilenamesEnv, icd);
178 
179     if (!mChangedICDEnv)
180     {
181         mICD = vk::ICD::Default;
182     }
183     return mChangedICDEnv;
184 }
185 
ChoosePhysicalDevice(const std::vector<VkPhysicalDevice> & physicalDevices,vk::ICD preferredICD,VkPhysicalDevice * physicalDeviceOut,VkPhysicalDeviceProperties * physicalDevicePropertiesOut)186 void ChoosePhysicalDevice(const std::vector<VkPhysicalDevice> &physicalDevices,
187                           vk::ICD preferredICD,
188                           VkPhysicalDevice *physicalDeviceOut,
189                           VkPhysicalDeviceProperties *physicalDevicePropertiesOut)
190 {
191     ASSERT(!physicalDevices.empty());
192 
193     ICDFilterFunc filter = GetFilterForICD(preferredICD);
194 
195     for (const VkPhysicalDevice &physicalDevice : physicalDevices)
196     {
197         vkGetPhysicalDeviceProperties(physicalDevice, physicalDevicePropertiesOut);
198         if (filter(*physicalDevicePropertiesOut))
199         {
200             *physicalDeviceOut = physicalDevice;
201             return;
202         }
203     }
204     WARN() << "Preferred device ICD not found. Using default physicalDevice instead.";
205 
206     // Fall back to first device.
207     *physicalDeviceOut = physicalDevices[0];
208     vkGetPhysicalDeviceProperties(*physicalDeviceOut, physicalDevicePropertiesOut);
209 }
210 
211 }  // namespace vk
212 
213 }  // namespace angle
214