tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

vulkan_icd.cpp (11820B)


      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/Optional.h"
     15 #include "common/bitset_utils.h"
     16 #include "common/debug.h"
     17 #include "common/system_utils.h"
     18 
     19 #include "common/vulkan/vk_google_filtering_precision.h"
     20 
     21 namespace
     22 {
     23 void ResetEnvironmentVar(const char *variableName, const Optional<std::string> &value)
     24 {
     25    if (!value.valid())
     26    {
     27        return;
     28    }
     29 
     30    if (value.value().empty())
     31    {
     32        angle::UnsetEnvironmentVar(variableName);
     33    }
     34    else
     35    {
     36        angle::SetEnvironmentVar(variableName, value.value().c_str());
     37    }
     38 }
     39 }  // namespace
     40 
     41 namespace angle
     42 {
     43 
     44 namespace vk
     45 {
     46 
     47 namespace
     48 {
     49 
     50 [[maybe_unused]] const std::string WrapICDEnvironment(const char *icdEnvironment)
     51 {
     52    // The libraries are bundled into the module directory
     53    std::string ret = ConcatenatePath(angle::GetModuleDirectory(), icdEnvironment);
     54    return ret;
     55 }
     56 
     57 [[maybe_unused]] constexpr char kLoaderLayersPathEnv[] = "VK_LAYER_PATH";
     58 [[maybe_unused]] constexpr char kLayerEnablesEnv[]     = "VK_LAYER_ENABLES";
     59 
     60 constexpr char kLoaderICDFilenamesEnv[]              = "VK_ICD_FILENAMES";
     61 constexpr char kANGLEPreferredDeviceEnv[]            = "ANGLE_PREFERRED_DEVICE";
     62 constexpr char kValidationLayersCustomSTypeListEnv[] = "VK_LAYER_CUSTOM_STYPE_LIST";
     63 constexpr char kNoDeviceSelect[]                     = "NODEVICE_SELECT";
     64 
     65 constexpr uint32_t kMockVendorID = 0xba5eba11;
     66 constexpr uint32_t kMockDeviceID = 0xf005ba11;
     67 constexpr char kMockDeviceName[] = "Vulkan Mock Device";
     68 
     69 constexpr uint32_t kGoogleVendorID      = 0x1AE0;
     70 constexpr uint32_t kSwiftShaderDeviceID = 0xC0DE;
     71 constexpr char kSwiftShaderDeviceName[] = "SwiftShader Device";
     72 
     73 using ICDFilterFunc = std::function<bool(const VkPhysicalDeviceProperties &)>;
     74 
     75 ICDFilterFunc GetFilterForICD(vk::ICD preferredICD)
     76 {
     77    switch (preferredICD)
     78    {
     79        case vk::ICD::Mock:
     80            return [](const VkPhysicalDeviceProperties &deviceProperties) {
     81                return ((deviceProperties.vendorID == kMockVendorID) &&
     82                        (deviceProperties.deviceID == kMockDeviceID) &&
     83                        (strcmp(deviceProperties.deviceName, kMockDeviceName) == 0));
     84            };
     85        case vk::ICD::SwiftShader:
     86            return [](const VkPhysicalDeviceProperties &deviceProperties) {
     87                return ((deviceProperties.vendorID == kGoogleVendorID) &&
     88                        (deviceProperties.deviceID == kSwiftShaderDeviceID) &&
     89                        (strncmp(deviceProperties.deviceName, kSwiftShaderDeviceName,
     90                                 strlen(kSwiftShaderDeviceName)) == 0));
     91            };
     92        default:
     93            const std::string anglePreferredDevice =
     94                angle::GetEnvironmentVar(kANGLEPreferredDeviceEnv);
     95            return [anglePreferredDevice](const VkPhysicalDeviceProperties &deviceProperties) {
     96                return (anglePreferredDevice == deviceProperties.deviceName);
     97            };
     98    }
     99 }
    100 
    101 }  // namespace
    102 
    103 // If we're loading the validation layers, we could be running from any random directory.
    104 // Change to the executable directory so we can find the layers, then change back to the
    105 // previous directory to be safe we don't disrupt the application.
    106 ScopedVkLoaderEnvironment::ScopedVkLoaderEnvironment(bool enableValidationLayers, vk::ICD icd)
    107    : mEnableValidationLayers(enableValidationLayers),
    108      mICD(icd),
    109      mChangedCWD(false),
    110      mChangedICDEnv(false),
    111      mChangedNoDeviceSelect(false)
    112 {
    113 // Changing CWD and setting environment variables makes no sense on Android,
    114 // since this code is a part of Java application there.
    115 // Android Vulkan loader doesn't need this either.
    116 #if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_GGP)
    117    if (icd == vk::ICD::Mock)
    118    {
    119        if (!setICDEnvironment(WrapICDEnvironment(ANGLE_VK_MOCK_ICD_JSON).c_str()))
    120        {
    121            ERR() << "Error setting environment for Mock/Null Driver.";
    122        }
    123    }
    124 #    if defined(ANGLE_VK_SWIFTSHADER_ICD_JSON)
    125    else if (icd == vk::ICD::SwiftShader)
    126    {
    127        if (!setICDEnvironment(WrapICDEnvironment(ANGLE_VK_SWIFTSHADER_ICD_JSON).c_str()))
    128        {
    129            ERR() << "Error setting environment for SwiftShader.";
    130        }
    131    }
    132 #    endif  // defined(ANGLE_VK_SWIFTSHADER_ICD_JSON)
    133 
    134 #    if !defined(ANGLE_PLATFORM_MACOS)
    135    if (mEnableValidationLayers || icd != vk::ICD::Default)
    136    {
    137        const auto &cwd = angle::GetCWD();
    138        if (!cwd.valid())
    139        {
    140            ERR() << "Error getting CWD for Vulkan layers init.";
    141            mEnableValidationLayers = false;
    142            mICD                    = vk::ICD::Default;
    143        }
    144        else
    145        {
    146            mPreviousCWD          = cwd.value();
    147            std::string moduleDir = angle::GetModuleDirectory();
    148            mChangedCWD           = angle::SetCWD(moduleDir.c_str());
    149            if (!mChangedCWD)
    150            {
    151                ERR() << "Error setting CWD for Vulkan layers init.";
    152                mEnableValidationLayers = false;
    153                mICD                    = vk::ICD::Default;
    154            }
    155        }
    156    }
    157 #    endif  // defined(ANGLE_PLATFORM_MACOS)
    158 
    159    // Override environment variable to use the ANGLE layers.
    160    if (mEnableValidationLayers)
    161    {
    162 #    if defined(ANGLE_VK_LAYERS_DIR)
    163        if (!angle::PrependPathToEnvironmentVar(kLoaderLayersPathEnv, ANGLE_VK_LAYERS_DIR))
    164        {
    165            ERR() << "Error setting environment for Vulkan layers init.";
    166            mEnableValidationLayers = false;
    167        }
    168 #    endif  // defined(ANGLE_VK_LAYERS_DIR)
    169 
    170        if (!angle::PrependPathToEnvironmentVar(
    171                kLayerEnablesEnv, "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION"))
    172        {
    173            ERR() << "Error setting synchronization validation environment for Vulkan validation "
    174                     "layers init.";
    175        }
    176 
    177        if (!setCustomExtensionsEnvironment())
    178        {
    179            ERR() << "Error setting custom list for custom extensions for Vulkan layers init.";
    180            mEnableValidationLayers = false;
    181        }
    182    }
    183 #endif  // !defined(ANGLE_PLATFORM_ANDROID)
    184 
    185    if (IsMSan() || IsASan())
    186    {
    187        // device select layer cause memory sanitizer false positive, so disable
    188        // it for msan build.
    189        mPreviousNoDeviceSelectEnv = angle::GetEnvironmentVar(kNoDeviceSelect);
    190        angle::SetEnvironmentVar(kNoDeviceSelect, "1");
    191        mChangedNoDeviceSelect = true;
    192    }
    193 }
    194 
    195 ScopedVkLoaderEnvironment::~ScopedVkLoaderEnvironment()
    196 {
    197    if (mChangedCWD)
    198    {
    199 #if !defined(ANGLE_PLATFORM_ANDROID)
    200        ASSERT(mPreviousCWD.valid());
    201        angle::SetCWD(mPreviousCWD.value().c_str());
    202 #endif  // !defined(ANGLE_PLATFORM_ANDROID)
    203    }
    204    if (mChangedICDEnv)
    205    {
    206        ResetEnvironmentVar(kLoaderICDFilenamesEnv, mPreviousICDEnv);
    207    }
    208 
    209    ResetEnvironmentVar(kValidationLayersCustomSTypeListEnv, mPreviousCustomExtensionsEnv);
    210 
    211    if (mChangedNoDeviceSelect)
    212    {
    213        ResetEnvironmentVar(kNoDeviceSelect, mPreviousNoDeviceSelectEnv);
    214    }
    215 }
    216 
    217 bool ScopedVkLoaderEnvironment::setICDEnvironment(const char *icd)
    218 {
    219    // Override environment variable to use built Mock ICD
    220    // ANGLE_VK_ICD_JSON gets set to the built mock ICD in BUILD.gn
    221    mPreviousICDEnv = angle::GetEnvironmentVar(kLoaderICDFilenamesEnv);
    222    mChangedICDEnv  = angle::SetEnvironmentVar(kLoaderICDFilenamesEnv, icd);
    223 
    224    if (!mChangedICDEnv)
    225    {
    226        mICD = vk::ICD::Default;
    227    }
    228    return mChangedICDEnv;
    229 }
    230 
    231 bool ScopedVkLoaderEnvironment::setCustomExtensionsEnvironment()
    232 {
    233    struct CustomExtension
    234    {
    235        VkStructureType type;
    236        size_t size;
    237    };
    238 
    239    CustomExtension customExtensions[] = {
    240 
    241        {VK_STRUCTURE_TYPE_SAMPLER_FILTERING_PRECISION_GOOGLE,
    242         sizeof(VkSamplerFilteringPrecisionGOOGLE)},
    243 
    244    };
    245 
    246    mPreviousCustomExtensionsEnv = angle::GetEnvironmentVar(kValidationLayersCustomSTypeListEnv);
    247 
    248    std::stringstream strstr;
    249    for (CustomExtension &extension : customExtensions)
    250    {
    251        if (strstr.tellp() != std::streampos(0))
    252        {
    253            strstr << angle::GetPathSeparatorForEnvironmentVar();
    254        }
    255 
    256        strstr << extension.type << angle::GetPathSeparatorForEnvironmentVar() << extension.size;
    257    }
    258 
    259    return angle::PrependPathToEnvironmentVar(kValidationLayersCustomSTypeListEnv,
    260                                              strstr.str().c_str());
    261 }
    262 
    263 void ChoosePhysicalDevice(PFN_vkGetPhysicalDeviceProperties pGetPhysicalDeviceProperties,
    264                          const std::vector<VkPhysicalDevice> &physicalDevices,
    265                          vk::ICD preferredICD,
    266                          uint32_t preferredVendorID,
    267                          uint32_t preferredDeviceID,
    268                          VkPhysicalDevice *physicalDeviceOut,
    269                          VkPhysicalDeviceProperties *physicalDevicePropertiesOut)
    270 {
    271    ASSERT(!physicalDevices.empty());
    272 
    273    ICDFilterFunc filter = GetFilterForICD(preferredICD);
    274 
    275    const bool shouldChooseByID = (preferredVendorID != 0 || preferredDeviceID != 0);
    276 
    277    for (const VkPhysicalDevice &physicalDevice : physicalDevices)
    278    {
    279        pGetPhysicalDeviceProperties(physicalDevice, physicalDevicePropertiesOut);
    280        if (filter(*physicalDevicePropertiesOut))
    281        {
    282            *physicalDeviceOut = physicalDevice;
    283            return;
    284        }
    285 
    286        if (shouldChooseByID)
    287        {
    288            // NOTE: If the system has multiple GPUs with the same vendor and
    289            // device IDs, this will arbitrarily select one of them.
    290            bool matchVendorID = true;
    291            bool matchDeviceID = true;
    292 
    293            if (preferredVendorID != 0 &&
    294                preferredVendorID != physicalDevicePropertiesOut->vendorID)
    295            {
    296                matchVendorID = false;
    297            }
    298 
    299            if (preferredDeviceID != 0 &&
    300                preferredDeviceID != physicalDevicePropertiesOut->deviceID)
    301            {
    302                matchDeviceID = false;
    303            }
    304 
    305            if (matchVendorID && matchDeviceID)
    306            {
    307                *physicalDeviceOut = physicalDevice;
    308                return;
    309            }
    310        }
    311    }
    312 
    313    Optional<VkPhysicalDevice> integratedDevice;
    314    VkPhysicalDeviceProperties integratedDeviceProperties;
    315    for (const VkPhysicalDevice &physicalDevice : physicalDevices)
    316    {
    317        pGetPhysicalDeviceProperties(physicalDevice, physicalDevicePropertiesOut);
    318        // If discrete GPU exists, uses it by default.
    319        if (physicalDevicePropertiesOut->deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
    320        {
    321            *physicalDeviceOut = physicalDevice;
    322            return;
    323        }
    324        if (physicalDevicePropertiesOut->deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU &&
    325            !integratedDevice.valid())
    326        {
    327            integratedDevice           = physicalDevice;
    328            integratedDeviceProperties = *physicalDevicePropertiesOut;
    329            continue;
    330        }
    331    }
    332 
    333    // If only integrated GPU exists, use it by default.
    334    if (integratedDevice.valid())
    335    {
    336        *physicalDeviceOut           = integratedDevice.value();
    337        *physicalDevicePropertiesOut = integratedDeviceProperties;
    338        return;
    339    }
    340 
    341    WARN() << "Preferred device ICD not found. Using default physicalDevice instead.";
    342    // Fallback to the first device.
    343    *physicalDeviceOut = physicalDevices[0];
    344    pGetPhysicalDeviceProperties(*physicalDeviceOut, physicalDevicePropertiesOut);
    345 }
    346 
    347 }  // namespace vk
    348 
    349 }  // namespace angle