|
|
|
@ -9,6 +9,7 @@
|
|
|
|
|
#include <fmt/format.h>
|
|
|
|
|
|
|
|
|
|
#include "common/assert.h"
|
|
|
|
|
#include "common/dynamic_library.h"
|
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
|
#include "common/telemetry.h"
|
|
|
|
|
#include "core/core.h"
|
|
|
|
@ -53,6 +54,45 @@ VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity_,
|
|
|
|
|
return VK_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Common::DynamicLibrary OpenVulkanLibrary() {
|
|
|
|
|
Common::DynamicLibrary library;
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
// Check if a path to a specific Vulkan library has been specified.
|
|
|
|
|
char* libvulkan_env = getenv("LIBVULKAN_PATH");
|
|
|
|
|
if (!libvulkan_env || !library.Open(libvulkan_env)) {
|
|
|
|
|
// Use the libvulkan.dylib from the application bundle.
|
|
|
|
|
std::string filename = File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
|
|
|
|
|
library.Open(filename.c_str());
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
|
|
|
|
|
if (!library.Open(filename.c_str())) {
|
|
|
|
|
// Android devices may not have libvulkan.so.1, only libvulkan.so.
|
|
|
|
|
filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
|
|
|
|
|
library.Open(filename.c_str());
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return library;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UniqueInstance CreateInstance(Common::DynamicLibrary& library, vk::DispatchLoaderDynamic& dld) {
|
|
|
|
|
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
|
|
|
|
if (!library.GetSymbol("vkGetInstanceProcAddr", &vkGetInstanceProcAddr)) {
|
|
|
|
|
return UniqueInstance{};
|
|
|
|
|
}
|
|
|
|
|
dld.init(vkGetInstanceProcAddr);
|
|
|
|
|
|
|
|
|
|
const vk::ApplicationInfo application_info("yuzu", VK_MAKE_VERSION(0, 1, 0), "yuzu",
|
|
|
|
|
VK_MAKE_VERSION(0, 1, 0), VK_API_VERSION_1_1);
|
|
|
|
|
const vk::InstanceCreateInfo instance_ci({}, &application_info, 0, nullptr, 0, nullptr);
|
|
|
|
|
vk::Instance unsafe_instance;
|
|
|
|
|
if (vk::createInstance(&instance_ci, nullptr, &unsafe_instance, dld) != vk::Result::eSuccess) {
|
|
|
|
|
return UniqueInstance{};
|
|
|
|
|
}
|
|
|
|
|
dld.init(unsafe_instance, vkGetInstanceProcAddr);
|
|
|
|
|
return UniqueInstance(unsafe_instance, {nullptr, dld});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string GetReadableVersion(u32 version) {
|
|
|
|
|
return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
|
|
|
|
|
VK_VERSION_PATCH(version));
|
|
|
|
@ -276,4 +316,33 @@ void RendererVulkan::Report() const {
|
|
|
|
|
telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> RendererVulkan::EnumerateDevices() {
|
|
|
|
|
Common::DynamicLibrary library = OpenVulkanLibrary();
|
|
|
|
|
if (!library.IsOpen()) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
vk::DispatchLoaderDynamic dld;
|
|
|
|
|
UniqueInstance instance = CreateInstance(library, dld);
|
|
|
|
|
if (!instance) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 num_devices;
|
|
|
|
|
if (instance->enumeratePhysicalDevices(&num_devices, nullptr, dld) != vk::Result::eSuccess) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
std::vector<vk::PhysicalDevice> devices(num_devices);
|
|
|
|
|
if (instance->enumeratePhysicalDevices(&num_devices, devices.data(), dld) !=
|
|
|
|
|
vk::Result::eSuccess) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> names;
|
|
|
|
|
names.reserve(num_devices);
|
|
|
|
|
for (auto& device : devices) {
|
|
|
|
|
names.push_back(device.getProperties(dld).deviceName);
|
|
|
|
|
}
|
|
|
|
|
return names;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Vulkan
|
|
|
|
|