duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

vulkan_loader.cpp (4510B)


      1 // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 // No better place for this..
      5 #define VMA_IMPLEMENTATION
      6 
      7 #include "vulkan_loader.h"
      8 
      9 #include "common/assert.h"
     10 #include "common/dynamic_library.h"
     11 #include "common/log.h"
     12 
     13 #include <cstdarg>
     14 #include <cstdio>
     15 #include <cstdlib>
     16 #include <cstring>
     17 #include <string>
     18 
     19 Log_SetChannel(VulkanDevice);
     20 
     21 extern "C" {
     22 
     23 #define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name name;
     24 #define VULKAN_INSTANCE_ENTRY_POINT(name, required) PFN_##name name;
     25 #define VULKAN_DEVICE_ENTRY_POINT(name, required) PFN_##name name;
     26 #include "vulkan_entry_points.inl"
     27 #undef VULKAN_DEVICE_ENTRY_POINT
     28 #undef VULKAN_INSTANCE_ENTRY_POINT
     29 #undef VULKAN_MODULE_ENTRY_POINT
     30 }
     31 
     32 void Vulkan::ResetVulkanLibraryFunctionPointers()
     33 {
     34 #define VULKAN_MODULE_ENTRY_POINT(name, required) name = nullptr;
     35 #define VULKAN_INSTANCE_ENTRY_POINT(name, required) name = nullptr;
     36 #define VULKAN_DEVICE_ENTRY_POINT(name, required) name = nullptr;
     37 #include "vulkan_entry_points.inl"
     38 #undef VULKAN_DEVICE_ENTRY_POINT
     39 #undef VULKAN_INSTANCE_ENTRY_POINT
     40 #undef VULKAN_MODULE_ENTRY_POINT
     41 }
     42 
     43 static DynamicLibrary s_vulkan_library;
     44 
     45 bool Vulkan::IsVulkanLibraryLoaded()
     46 {
     47   return s_vulkan_library.IsOpen();
     48 }
     49 
     50 bool Vulkan::LoadVulkanLibrary(Error* error)
     51 {
     52   AssertMsg(!s_vulkan_library.IsOpen(), "Vulkan module is not loaded.");
     53 
     54 #ifdef __APPLE__
     55   // Check if a path to a specific Vulkan library has been specified.
     56   char* libvulkan_env = getenv("LIBVULKAN_PATH");
     57   if (libvulkan_env)
     58     s_vulkan_library.Open(libvulkan_env, error);
     59   if (!s_vulkan_library.IsOpen() &&
     60       !s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("MoltenVK").c_str(), error))
     61   {
     62     return false;
     63   }
     64 #else
     65   // try versioned first, then unversioned.
     66   if (!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan", 1).c_str(), error) &&
     67       !s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan").c_str(), error))
     68   {
     69     return false;
     70   }
     71 #endif
     72 
     73   bool required_functions_missing = false;
     74 
     75 #define VULKAN_MODULE_ENTRY_POINT(name, required)                                                                      \
     76   if (!s_vulkan_library.GetSymbol(#name, &name))                                                                       \
     77   {                                                                                                                    \
     78     ERROR_LOG("Vulkan: Failed to load required module function {}", #name);                                            \
     79     required_functions_missing = true;                                                                                 \
     80   }
     81 #include "vulkan_entry_points.inl"
     82 #undef VULKAN_MODULE_ENTRY_POINT
     83 
     84   if (required_functions_missing)
     85   {
     86     ResetVulkanLibraryFunctionPointers();
     87     s_vulkan_library.Close();
     88     return false;
     89   }
     90 
     91   return true;
     92 }
     93 
     94 void Vulkan::UnloadVulkanLibrary()
     95 {
     96   ResetVulkanLibraryFunctionPointers();
     97   s_vulkan_library.Close();
     98 }
     99 
    100 bool Vulkan::LoadVulkanInstanceFunctions(VkInstance instance)
    101 {
    102   bool required_functions_missing = false;
    103   auto LoadFunction = [&](PFN_vkVoidFunction* func_ptr, const char* name, bool is_required) {
    104     *func_ptr = vkGetInstanceProcAddr(instance, name);
    105     if (!(*func_ptr) && is_required)
    106     {
    107       ERROR_LOG("Vulkan: Failed to load required instance function {}", name);
    108       required_functions_missing = true;
    109     }
    110   };
    111 
    112 #define VULKAN_INSTANCE_ENTRY_POINT(name, required)                                                                    \
    113   LoadFunction(reinterpret_cast<PFN_vkVoidFunction*>(&name), #name, required);
    114 #include "vulkan_entry_points.inl"
    115 #undef VULKAN_INSTANCE_ENTRY_POINT
    116 
    117   return !required_functions_missing;
    118 }
    119 
    120 bool Vulkan::LoadVulkanDeviceFunctions(VkDevice device)
    121 {
    122   bool required_functions_missing = false;
    123   auto LoadFunction = [&](PFN_vkVoidFunction* func_ptr, const char* name, bool is_required) {
    124     *func_ptr = vkGetDeviceProcAddr(device, name);
    125     if (!(*func_ptr) && is_required)
    126     {
    127       ERROR_LOG("Vulkan: Failed to load required device function {}", name);
    128       required_functions_missing = true;
    129     }
    130   };
    131 
    132 #define VULKAN_DEVICE_ENTRY_POINT(name, required)                                                                      \
    133   LoadFunction(reinterpret_cast<PFN_vkVoidFunction*>(&name), #name, required);
    134 #include "vulkan_entry_points.inl"
    135 #undef VULKAN_DEVICE_ENTRY_POINT
    136 
    137   return !required_functions_missing;
    138 }