mirror of https://github.com/PCSX2/pcsx2.git
parent
6545c62d26
commit
0628e8cc87
|
@ -17,6 +17,8 @@ namespace CocoaTools
|
||||||
void AddThemeChangeHandler(void* ctx, void(handler)(void* ctx));
|
void AddThemeChangeHandler(void* ctx, void(handler)(void* ctx));
|
||||||
/// Remove a handler previously added using AddThemeChangeHandler with the given context
|
/// Remove a handler previously added using AddThemeChangeHandler with the given context
|
||||||
void RemoveThemeChangeHandler(void* ctx);
|
void RemoveThemeChangeHandler(void* ctx);
|
||||||
|
/// 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();
|
||||||
/// Move the given file to the trash, and return the path to its new location
|
/// Move the given file to the trash, and return the path to its new location
|
||||||
|
|
|
@ -133,6 +133,17 @@ bool Common::PlaySoundAsync(const char* path)
|
||||||
|
|
||||||
// MARK: - Updater
|
// MARK: - Updater
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
#include "common/Console.h"
|
#include "common/Console.h"
|
||||||
#include "common/Error.h"
|
#include "common/Error.h"
|
||||||
|
#include "common/FileSystem.h"
|
||||||
#include "common/SmallString.h"
|
#include "common/SmallString.h"
|
||||||
|
#include "common/Path.h"
|
||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -15,6 +17,9 @@
|
||||||
#include "common/RedtapeWindows.h"
|
#include "common/RedtapeWindows.h"
|
||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "common/CocoaTools.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DynamicLibrary::DynamicLibrary() = default;
|
DynamicLibrary::DynamicLibrary() = default;
|
||||||
|
@ -91,6 +96,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;
|
||||||
|
|
|
@ -30,6 +30,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);
|
||||||
|
|
|
@ -66,6 +66,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);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||||
// SPDX-License-Identifier: LGPL-3.0+
|
// SPDX-License-Identifier: LGPL-3.0+
|
||||||
|
|
||||||
#include "GS/GS.h"
|
#include "GS/GS.h"
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "common/Console.h"
|
#include "common/Console.h"
|
||||||
#include "common/BitUtils.h"
|
#include "common/BitUtils.h"
|
||||||
|
#include "common/Error.h"
|
||||||
#include "common/HostSys.h"
|
#include "common/HostSys.h"
|
||||||
#include "common/Path.h"
|
#include "common/Path.h"
|
||||||
#include "common/ScopedGuard.h"
|
#include "common/ScopedGuard.h"
|
||||||
|
@ -373,8 +374,7 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab
|
||||||
m_optional_extensions.vk_ext_calibrated_timestamps =
|
m_optional_extensions.vk_ext_calibrated_timestamps =
|
||||||
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
|
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
|
||||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access =
|
m_optional_extensions.vk_ext_rasterization_order_attachment_access =
|
||||||
SupportsExtension(VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false) ||
|
SupportsExtension(VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false);
|
||||||
SupportsExtension(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false);
|
|
||||||
m_optional_extensions.vk_ext_line_rasterization = SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME,
|
m_optional_extensions.vk_ext_line_rasterization = SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME,
|
||||||
require_line_rasterization);
|
require_line_rasterization);
|
||||||
m_optional_extensions.vk_khr_driver_properties = SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
m_optional_extensions.vk_khr_driver_properties = SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
||||||
|
@ -2029,9 +2029,8 @@ void GSDeviceVK::GetAdaptersAndFullscreenModes(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Vulkan::LoadVulkanLibrary())
|
if (Vulkan::LoadVulkanLibrary(nullptr))
|
||||||
{
|
{
|
||||||
ScopedGuard lib_guard([]() { Vulkan::UnloadVulkanLibrary(); });
|
|
||||||
const VkInstance instance = CreateVulkanInstance(WindowInfo(), false, false);
|
const VkInstance instance = CreateVulkanInstance(WindowInfo(), false, false);
|
||||||
if (instance != VK_NULL_HANDLE)
|
if (instance != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
|
@ -2040,6 +2039,8 @@ void GSDeviceVK::GetAdaptersAndFullscreenModes(
|
||||||
|
|
||||||
vkDestroyInstance(instance, nullptr);
|
vkDestroyInstance(instance, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vulkan::UnloadVulkanLibrary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2497,9 +2498,11 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
|
||||||
bool enable_debug_utils = GSConfig.UseDebugDevice;
|
bool enable_debug_utils = GSConfig.UseDebugDevice;
|
||||||
bool enable_validation_layer = GSConfig.UseDebugDevice;
|
bool enable_validation_layer = GSConfig.UseDebugDevice;
|
||||||
|
|
||||||
if (!Vulkan::LoadVulkanLibrary())
|
Error error;
|
||||||
|
if (!Vulkan::LoadVulkanLibrary(&error))
|
||||||
{
|
{
|
||||||
Host::ReportErrorAsync("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:\n");
|
||||||
|
Host::ReportErrorAsync("Error", error.GetDescription());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||||
// SPDX-License-Identifier: LGPL-3.0+
|
// SPDX-License-Identifier: LGPL-3.0+
|
||||||
|
|
||||||
#include "GS/Renderers/Vulkan/VKLoader.h"
|
#include "GS/Renderers/Vulkan/VKLoader.h"
|
||||||
|
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
|
#include "common/Console.h"
|
||||||
|
#include "common/DynamicLibrary.h"
|
||||||
|
#include "common/Error.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -11,14 +14,6 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <mach-o/dyld.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
#define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name name;
|
#define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name name;
|
||||||
|
@ -41,134 +36,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)
|
||||||
{
|
{
|
||||||
pxAssertRel(!s_vulkan_module, "Vulkan module is not loaded.");
|
pxAssertRel(!s_vulkan_library.IsOpen(), "Vulkan module is not loaded.");
|
||||||
|
|
||||||
s_vulkan_module = LoadLibraryA("vulkan-1.dll");
|
#ifdef __APPLE__
|
||||||
if (!s_vulkan_module)
|
|
||||||
{
|
|
||||||
std::fprintf(stderr, "Failed to load vulkan-1.dll\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool required_functions_missing = false;
|
|
||||||
auto LoadFunction = [&required_functions_missing](FARPROC* func_ptr, const char* name, bool is_required) {
|
|
||||||
*func_ptr = GetProcAddress(s_vulkan_module, name);
|
|
||||||
if (!(*func_ptr) && is_required)
|
|
||||||
{
|
|
||||||
std::fprintf(stderr, "Vulkan: Failed to load required module function %s\n", name);
|
|
||||||
required_functions_missing = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VULKAN_MODULE_ENTRY_POINT(name, required) LoadFunction(reinterpret_cast<FARPROC*>(&name), #name, required);
|
|
||||||
#include "VKEntryPoints.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()
|
|
||||||
{
|
|
||||||
pxAssertRel(!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)
|
|
||||||
{
|
|
||||||
std::fprintf(stderr, "Failed to load or locate libvulkan.so\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool required_functions_missing = false;
|
bool required_functions_missing = false;
|
||||||
auto LoadFunction = [&required_functions_missing](void** func_ptr, const char* name, bool is_required) {
|
#define VULKAN_MODULE_ENTRY_POINT(name, required) \
|
||||||
*func_ptr = dlsym(s_vulkan_module, name);
|
if (!s_vulkan_library.GetSymbol(#name, &name)) \
|
||||||
if (!(*func_ptr) && is_required)
|
{ \
|
||||||
{
|
ERROR_LOG("Vulkan: Failed to load required module function {}", #name); \
|
||||||
std::fprintf(stderr, "Vulkan: Failed to load required module function %s\n", name);
|
required_functions_missing = true; \
|
||||||
required_functions_missing = true;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
#define VULKAN_MODULE_ENTRY_POINT(name, required) LoadFunction(reinterpret_cast<void**>(&name), #name, required);
|
|
||||||
#include "VKEntryPoints.inl"
|
#include "VKEntryPoints.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,13 +90,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: 2002-2023 PCSX2 Dev Team
|
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||||
// SPDX-License-Identifier: LGPL-3.0+
|
// SPDX-License-Identifier: LGPL-3.0+
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
class Error;
|
||||||
|
|
||||||
#define VK_NO_PROTOTYPES
|
#define VK_NO_PROTOTYPES
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -86,7 +88,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 New Issue