mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 22:05:38 +00:00
Vulkan: Simplify loader using DynamicLibrary
This commit is contained in:
parent
88ace6e4ae
commit
8e3284d8c6
|
@ -31,6 +31,9 @@ void RemoveThemeChangeHandler(void* ctx);
|
||||||
/// Moves a file from one location to another, using NSFileManager.
|
/// Moves a file from one location to another, using NSFileManager.
|
||||||
bool MoveFile(const char* source, const char* destination, Error* error);
|
bool MoveFile(const char* source, const char* destination, Error* error);
|
||||||
|
|
||||||
|
/// Returns the bundle path.
|
||||||
|
std::optional<std::string> GetBundlePath();
|
||||||
|
|
||||||
/// Get the bundle path to the actual application without any translocation fun
|
/// Get the bundle path to the actual application without any translocation fun
|
||||||
std::optional<std::string> GetNonTranslocatedBundlePath();
|
std::optional<std::string> GetNonTranslocatedBundlePath();
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,17 @@ void CocoaTools::RemoveThemeChangeHandler(void* ctx)
|
||||||
[s_themeChangeHandler removeCallback:ctx];
|
[s_themeChangeHandler removeCallback:ctx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> CocoaTools::GetBundlePath()
|
||||||
|
{
|
||||||
|
std::optional<std::string> ret;
|
||||||
|
@autoreleasepool {
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
|
||||||
|
if (url)
|
||||||
|
ret = std::string([url fileSystemRepresentation]);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::string> CocoaTools::GetNonTranslocatedBundlePath()
|
std::optional<std::string> CocoaTools::GetNonTranslocatedBundlePath()
|
||||||
{
|
{
|
||||||
// See https://objective-see.com/blog/blog_0x15.html
|
// See https://objective-see.com/blog/blog_0x15.html
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
#include "common/dynamic_library.h"
|
#include "common/dynamic_library.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
|
#include "common/file_system.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
#include "common/path.h"
|
||||||
#include "common/small_string.h"
|
#include "common/small_string.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
|
||||||
|
@ -15,6 +17,9 @@
|
||||||
#include "common/windows_headers.h"
|
#include "common/windows_headers.h"
|
||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/cocoa_tools.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Log_SetChannel(DynamicLibrary);
|
Log_SetChannel(DynamicLibrary);
|
||||||
|
@ -92,6 +97,27 @@ bool DynamicLibrary::Open(const char* filename, Error* error)
|
||||||
m_handle = dlopen(filename, RTLD_NOW);
|
m_handle = dlopen(filename, RTLD_NOW);
|
||||||
if (!m_handle)
|
if (!m_handle)
|
||||||
{
|
{
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// On MacOS, try searching in Frameworks.
|
||||||
|
if (!Path::IsAbsolute(filename))
|
||||||
|
{
|
||||||
|
std::optional<std::string> bundle_path = CocoaTools::GetBundlePath();
|
||||||
|
if (bundle_path.has_value())
|
||||||
|
{
|
||||||
|
std::string frameworks_path = fmt::format("{}/Contents/Frameworks/{}", bundle_path.value(), filename);
|
||||||
|
if (FileSystem::FileExists(frameworks_path.c_str()))
|
||||||
|
{
|
||||||
|
m_handle = dlopen(frameworks_path.c_str(), RTLD_NOW);
|
||||||
|
if (m_handle)
|
||||||
|
{
|
||||||
|
Error::Clear(error);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const char* err = dlerror();
|
const char* err = dlerror();
|
||||||
Error::SetStringFmt(error, "Loading {} failed: {}", filename, err ? err : "<UNKNOWN>");
|
Error::SetStringFmt(error, "Loading {} failed: {}", filename, err ? err : "<UNKNOWN>");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -28,6 +28,12 @@ void Error::Clear()
|
||||||
m_description = {};
|
m_description = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Error::Clear(Error* errptr)
|
||||||
|
{
|
||||||
|
if (errptr)
|
||||||
|
errptr->Clear();
|
||||||
|
}
|
||||||
|
|
||||||
void Error::SetErrno(int err)
|
void Error::SetErrno(int err)
|
||||||
{
|
{
|
||||||
SetErrno(std::string_view(), err);
|
SetErrno(std::string_view(), err);
|
||||||
|
|
|
@ -68,6 +68,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// helpers for setting
|
// helpers for setting
|
||||||
|
static void Clear(Error* errptr);
|
||||||
static void SetErrno(Error* errptr, int err);
|
static void SetErrno(Error* errptr, int err);
|
||||||
static void SetErrno(Error* errptr, std::string_view prefix, int err);
|
static void SetErrno(Error* errptr, std::string_view prefix, int err);
|
||||||
static void SetSocket(Error* errptr, int err);
|
static void SetSocket(Error* errptr, int err);
|
||||||
|
|
|
@ -1112,11 +1112,9 @@ std::unique_ptr<GPUDevice> GPUDevice::CreateDeviceForAPI(RenderAPI api)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_VULKAN) || defined(__APPLE__)
|
#if defined(ENABLE_VULKAN) || defined(__APPLE__)
|
||||||
#define SHADERC_INIT_FUNCTIONS(X) \
|
|
||||||
X(shaderc_compiler_initialize) \
|
|
||||||
X(shaderc_compiler_release)
|
|
||||||
|
|
||||||
#define SHADERC_FUNCTIONS(X) \
|
#define SHADERC_FUNCTIONS(X) \
|
||||||
|
X(shaderc_compiler_initialize) \
|
||||||
|
X(shaderc_compiler_release) \
|
||||||
X(shaderc_compile_options_initialize) \
|
X(shaderc_compile_options_initialize) \
|
||||||
X(shaderc_compile_options_release) \
|
X(shaderc_compile_options_release) \
|
||||||
X(shaderc_compile_options_set_source_language) \
|
X(shaderc_compile_options_set_source_language) \
|
||||||
|
@ -1134,9 +1132,10 @@ std::unique_ptr<GPUDevice> GPUDevice::CreateDeviceForAPI(RenderAPI api)
|
||||||
// TODO: NOT thread safe, yet.
|
// TODO: NOT thread safe, yet.
|
||||||
namespace dyn_shaderc {
|
namespace dyn_shaderc {
|
||||||
static bool Open();
|
static bool Open();
|
||||||
|
static void Close();
|
||||||
|
|
||||||
static DynamicLibrary s_library;
|
static DynamicLibrary s_library;
|
||||||
static std::unique_ptr<struct shaderc_compiler, void (*)(shaderc_compiler_t)> s_compiler(nullptr, nullptr);
|
static shaderc_compiler_t s_compiler = nullptr;
|
||||||
|
|
||||||
#define ADD_FUNC(F) static decltype(&::F) F;
|
#define ADD_FUNC(F) static decltype(&::F) F;
|
||||||
SHADERC_FUNCTIONS(ADD_FUNC)
|
SHADERC_FUNCTIONS(ADD_FUNC)
|
||||||
|
@ -1167,27 +1166,40 @@ bool dyn_shaderc::Open()
|
||||||
if (!s_library.GetSymbol(#F, &F)) \
|
if (!s_library.GetSymbol(#F, &F)) \
|
||||||
{ \
|
{ \
|
||||||
Log_ErrorFmt("Failed to find function {}", #F); \
|
Log_ErrorFmt("Failed to find function {}", #F); \
|
||||||
s_library.Close(); \
|
Close(); \
|
||||||
return false; \
|
|
||||||
}
|
|
||||||
#define LOAD_INIT_FUNC(F) \
|
|
||||||
decltype(&::F) p##F; \
|
|
||||||
if (!s_library.GetSymbol(#F, &p##F)) \
|
|
||||||
{ \
|
|
||||||
Log_ErrorFmt("Failed to find function {}", #F); \
|
|
||||||
s_library.Close(); \
|
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
SHADERC_FUNCTIONS(LOAD_FUNC)
|
SHADERC_FUNCTIONS(LOAD_FUNC)
|
||||||
SHADERC_INIT_FUNCTIONS(LOAD_INIT_FUNC)
|
|
||||||
#undef LOAD_FUNC
|
#undef LOAD_FUNC
|
||||||
#undef LOAD_INIT_FUNC
|
|
||||||
|
|
||||||
s_compiler = decltype(s_compiler)(pshaderc_compiler_initialize(), pshaderc_compiler_release);
|
s_compiler = shaderc_compiler_initialize();
|
||||||
|
if (!s_compiler)
|
||||||
|
{
|
||||||
|
Log_ErrorPrint("shaderc_compiler_initialize() failed");
|
||||||
|
Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atexit(&dyn_shaderc::Close);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dyn_shaderc::Close()
|
||||||
|
{
|
||||||
|
if (s_compiler)
|
||||||
|
{
|
||||||
|
shaderc_compiler_release(s_compiler);
|
||||||
|
s_compiler = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNLOAD_FUNC(F) F = nullptr;
|
||||||
|
SHADERC_FUNCTIONS(UNLOAD_FUNC)
|
||||||
|
#undef UNLOAD_FUNC
|
||||||
|
|
||||||
|
s_library.Close();
|
||||||
|
}
|
||||||
|
|
||||||
#undef SHADERC_FUNCTIONS
|
#undef SHADERC_FUNCTIONS
|
||||||
#undef SHADERC_INIT_FUNCTIONS
|
#undef SHADERC_INIT_FUNCTIONS
|
||||||
|
|
||||||
|
@ -1216,7 +1228,7 @@ bool GPUDevice::CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, std::string_v
|
||||||
|
|
||||||
shaderc_compilation_result_t result;
|
shaderc_compilation_result_t result;
|
||||||
const shaderc_compilation_status status = dyn_shaderc::shaderc_compile_into_spv(
|
const shaderc_compilation_status status = dyn_shaderc::shaderc_compile_into_spv(
|
||||||
dyn_shaderc::s_compiler.get(), source.data(), source.length(), stage_kinds[static_cast<size_t>(stage)], "source",
|
dyn_shaderc::s_compiler, source.data(), source.length(), stage_kinds[static_cast<size_t>(stage)], "source",
|
||||||
entry_point, options, &result);
|
entry_point, options, &result);
|
||||||
if (status != shaderc_compilation_status_success)
|
if (status != shaderc_compilation_status_success)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1845,7 +1845,7 @@ GPUDevice::AdapterAndModeList VulkanDevice::StaticGetAdapterAndModeList()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Vulkan::LoadVulkanLibrary())
|
if (Vulkan::LoadVulkanLibrary(nullptr))
|
||||||
{
|
{
|
||||||
ScopedGuard lib_guard([]() { Vulkan::UnloadVulkanLibrary(); });
|
ScopedGuard lib_guard([]() { Vulkan::UnloadVulkanLibrary(); });
|
||||||
OptionalExtensions oe = {};
|
OptionalExtensions oe = {};
|
||||||
|
@ -1857,6 +1857,8 @@ GPUDevice::AdapterAndModeList VulkanDevice::StaticGetAdapterAndModeList()
|
||||||
|
|
||||||
vkDestroyInstance(instance, nullptr);
|
vkDestroyInstance(instance, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vulkan::UnloadVulkanLibrary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1925,9 +1927,10 @@ bool VulkanDevice::CreateDevice(std::string_view adapter, bool threaded_presenta
|
||||||
bool enable_debug_utils = m_debug_device;
|
bool enable_debug_utils = m_debug_device;
|
||||||
bool enable_validation_layer = m_debug_device;
|
bool enable_validation_layer = m_debug_device;
|
||||||
|
|
||||||
if (!Vulkan::LoadVulkanLibrary())
|
if (!Vulkan::LoadVulkanLibrary(error))
|
||||||
{
|
{
|
||||||
Error::SetStringView(error, "Failed to load Vulkan library. Does your GPU and/or driver support Vulkan?");
|
Error::AddPrefix(error,
|
||||||
|
"Failed to load Vulkan library. Does your GPU and/or driver support Vulkan?\nThe error was:");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "vulkan_loader.h"
|
#include "vulkan_loader.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/dynamic_library.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
@ -15,14 +16,6 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <mach-o/dyld.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Log_SetChannel(VulkanDevice);
|
Log_SetChannel(VulkanDevice);
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -47,134 +40,51 @@ void Vulkan::ResetVulkanLibraryFunctionPointers()
|
||||||
#undef VULKAN_MODULE_ENTRY_POINT
|
#undef VULKAN_MODULE_ENTRY_POINT
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
static DynamicLibrary s_vulkan_library;
|
||||||
|
|
||||||
static HMODULE s_vulkan_module;
|
|
||||||
|
|
||||||
bool Vulkan::IsVulkanLibraryLoaded()
|
bool Vulkan::IsVulkanLibraryLoaded()
|
||||||
{
|
{
|
||||||
return s_vulkan_module != NULL;
|
return s_vulkan_library.IsOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Vulkan::LoadVulkanLibrary()
|
bool Vulkan::LoadVulkanLibrary(Error* error)
|
||||||
{
|
{
|
||||||
AssertMsg(!s_vulkan_module, "Vulkan module is not loaded.");
|
AssertMsg(!s_vulkan_library.IsOpen(), "Vulkan module is not loaded.");
|
||||||
|
|
||||||
s_vulkan_module = LoadLibraryA("vulkan-1.dll");
|
#ifdef __APPLE__
|
||||||
if (!s_vulkan_module)
|
|
||||||
{
|
|
||||||
Log_ErrorPrintf("Failed to load vulkan-1.dll");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool required_functions_missing = false;
|
|
||||||
auto LoadFunction = [&](FARPROC* func_ptr, const char* name, bool is_required) {
|
|
||||||
*func_ptr = GetProcAddress(s_vulkan_module, name);
|
|
||||||
if (!(*func_ptr) && is_required)
|
|
||||||
{
|
|
||||||
Log_ErrorPrintf("Vulkan: Failed to load required module function %s", name);
|
|
||||||
required_functions_missing = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VULKAN_MODULE_ENTRY_POINT(name, required) LoadFunction(reinterpret_cast<FARPROC*>(&name), #name, required);
|
|
||||||
#include "vulkan_entry_points.inl"
|
|
||||||
#undef VULKAN_MODULE_ENTRY_POINT
|
|
||||||
|
|
||||||
if (required_functions_missing)
|
|
||||||
{
|
|
||||||
ResetVulkanLibraryFunctionPointers();
|
|
||||||
FreeLibrary(s_vulkan_module);
|
|
||||||
s_vulkan_module = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Vulkan::UnloadVulkanLibrary()
|
|
||||||
{
|
|
||||||
ResetVulkanLibraryFunctionPointers();
|
|
||||||
if (s_vulkan_module)
|
|
||||||
FreeLibrary(s_vulkan_module);
|
|
||||||
s_vulkan_module = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static void* s_vulkan_module;
|
|
||||||
|
|
||||||
bool Vulkan::IsVulkanLibraryLoaded()
|
|
||||||
{
|
|
||||||
return s_vulkan_module != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vulkan::LoadVulkanLibrary()
|
|
||||||
{
|
|
||||||
AssertMsg(!s_vulkan_module, "Vulkan module is not loaded.");
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
// Check if a path to a specific Vulkan library has been specified.
|
// Check if a path to a specific Vulkan library has been specified.
|
||||||
char* libvulkan_env = getenv("LIBVULKAN_PATH");
|
char* libvulkan_env = getenv("LIBVULKAN_PATH");
|
||||||
if (libvulkan_env)
|
if (libvulkan_env)
|
||||||
s_vulkan_module = dlopen(libvulkan_env, RTLD_NOW);
|
s_vulkan_library.Open(libvulkan_env, error);
|
||||||
if (!s_vulkan_module)
|
if (!s_vulkan_library.IsOpen() &&
|
||||||
|
!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("MoltenVK").c_str(), error))
|
||||||
{
|
{
|
||||||
unsigned path_size = 0;
|
return false;
|
||||||
_NSGetExecutablePath(nullptr, &path_size);
|
|
||||||
std::string path;
|
|
||||||
path.resize(path_size);
|
|
||||||
if (_NSGetExecutablePath(path.data(), &path_size) == 0)
|
|
||||||
{
|
|
||||||
path[path_size] = 0;
|
|
||||||
|
|
||||||
size_t pos = path.rfind('/');
|
|
||||||
if (pos != std::string::npos)
|
|
||||||
{
|
|
||||||
path.erase(pos);
|
|
||||||
path += "/../Frameworks/libMoltenVK.dylib";
|
|
||||||
s_vulkan_module = dlopen(path.c_str(), RTLD_NOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!s_vulkan_module)
|
|
||||||
s_vulkan_module = dlopen("libvulkan.dylib", RTLD_NOW);
|
|
||||||
#else
|
#else
|
||||||
// Names of libraries to search. Desktop should use libvulkan.so.1 or libvulkan.so.
|
// try versioned first, then unversioned.
|
||||||
static const char* search_lib_names[] = {"libvulkan.so.1", "libvulkan.so"};
|
if (!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan", 1).c_str(), error) &&
|
||||||
for (size_t i = 0; i < sizeof(search_lib_names) / sizeof(search_lib_names[0]); i++)
|
!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan").c_str(), error))
|
||||||
{
|
{
|
||||||
s_vulkan_module = dlopen(search_lib_names[i], RTLD_NOW);
|
return false;
|
||||||
if (s_vulkan_module)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!s_vulkan_module)
|
|
||||||
{
|
|
||||||
Log_ErrorPrintf("Failed to load or locate libvulkan.so");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool required_functions_missing = false;
|
bool required_functions_missing = false;
|
||||||
auto LoadFunction = [&](void** func_ptr, const char* name, bool is_required) {
|
|
||||||
*func_ptr = dlsym(s_vulkan_module, name);
|
|
||||||
if (!(*func_ptr) && is_required)
|
|
||||||
{
|
|
||||||
Log_ErrorPrintf("Vulkan: Failed to load required module function %s", name);
|
|
||||||
required_functions_missing = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VULKAN_MODULE_ENTRY_POINT(name, required) LoadFunction(reinterpret_cast<void**>(&name), #name, required);
|
#define VULKAN_MODULE_ENTRY_POINT(name, required) \
|
||||||
|
if (!s_vulkan_library.GetSymbol(#name, &name)) \
|
||||||
|
{ \
|
||||||
|
Log_ErrorFmt("Vulkan: Failed to load required module function {}", #name); \
|
||||||
|
required_functions_missing = true; \
|
||||||
|
}
|
||||||
#include "vulkan_entry_points.inl"
|
#include "vulkan_entry_points.inl"
|
||||||
#undef VULKAN_MODULE_ENTRY_POINT
|
#undef VULKAN_MODULE_ENTRY_POINT
|
||||||
|
|
||||||
if (required_functions_missing)
|
if (required_functions_missing)
|
||||||
{
|
{
|
||||||
ResetVulkanLibraryFunctionPointers();
|
ResetVulkanLibraryFunctionPointers();
|
||||||
dlclose(s_vulkan_module);
|
s_vulkan_library.Close();
|
||||||
s_vulkan_module = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,13 +94,9 @@ bool Vulkan::LoadVulkanLibrary()
|
||||||
void Vulkan::UnloadVulkanLibrary()
|
void Vulkan::UnloadVulkanLibrary()
|
||||||
{
|
{
|
||||||
ResetVulkanLibraryFunctionPointers();
|
ResetVulkanLibraryFunctionPointers();
|
||||||
if (s_vulkan_module)
|
s_vulkan_library.Close();
|
||||||
dlclose(s_vulkan_module);
|
|
||||||
s_vulkan_module = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool Vulkan::LoadVulkanInstanceFunctions(VkInstance instance)
|
bool Vulkan::LoadVulkanInstanceFunctions(VkInstance instance)
|
||||||
{
|
{
|
||||||
bool required_functions_missing = false;
|
bool required_functions_missing = false;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
class Error;
|
||||||
|
|
||||||
#define VK_NO_PROTOTYPES
|
#define VK_NO_PROTOTYPES
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -93,7 +95,7 @@
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
bool IsVulkanLibraryLoaded();
|
bool IsVulkanLibraryLoaded();
|
||||||
bool LoadVulkanLibrary();
|
bool LoadVulkanLibrary(Error* error);
|
||||||
bool LoadVulkanInstanceFunctions(VkInstance instance);
|
bool LoadVulkanInstanceFunctions(VkInstance instance);
|
||||||
bool LoadVulkanDeviceFunctions(VkDevice device);
|
bool LoadVulkanDeviceFunctions(VkDevice device);
|
||||||
void UnloadVulkanLibrary();
|
void UnloadVulkanLibrary();
|
||||||
|
|
Loading…
Reference in a new issue