Introduce QuirkManager for runtime GPU quirk tracking

We require a way to track certain host GPU features that are optional such as Vulkan extensions, this is what the `QuirkManager` class does as it checks for all quirks and holds them allowing other components to branch based off these quirks.
This commit is contained in:
PixelyIon 2021-11-12 01:23:46 +05:30
parent 8803616673
commit 8ef225a37d
6 changed files with 65 additions and 9 deletions

View File

@ -129,6 +129,7 @@ add_library(skyline SHARED
${source_DIR}/skyline/audio/resampler.cpp ${source_DIR}/skyline/audio/resampler.cpp
${source_DIR}/skyline/audio/adpcm_decoder.cpp ${source_DIR}/skyline/audio/adpcm_decoder.cpp
${source_DIR}/skyline/gpu.cpp ${source_DIR}/skyline/gpu.cpp
${source_DIR}/skyline/gpu/quirk_manager.cpp
${source_DIR}/skyline/gpu/memory_manager.cpp ${source_DIR}/skyline/gpu/memory_manager.cpp
${source_DIR}/skyline/gpu/texture_manager.cpp ${source_DIR}/skyline/gpu/texture_manager.cpp
${source_DIR}/skyline/gpu/command_scheduler.cpp ${source_DIR}/skyline/gpu/command_scheduler.cpp

View File

@ -119,17 +119,18 @@ namespace skyline::gpu {
return std::move(vk::raii::PhysicalDevices(instance).front()); // We just select the first device as we aren't expecting multiple GPUs return std::move(vk::raii::PhysicalDevices(instance).front()); // We just select the first device as we aren't expecting multiple GPUs
} }
vk::raii::Device GPU::CreateDevice(const vk::raii::PhysicalDevice &physicalDevice, typeof(vk::DeviceQueueCreateInfo::queueCount) &vkQueueFamilyIndex) { vk::raii::Device GPU::CreateDevice(const vk::raii::PhysicalDevice &physicalDevice, typeof(vk::DeviceQueueCreateInfo::queueCount) &vkQueueFamilyIndex, QuirkManager& quirks) {
auto properties{physicalDevice.getProperties()}; // We should check for required properties here, if/when we have them auto properties{physicalDevice.getProperties()};
auto features{physicalDevice.getFeatures2()};
auto extensions{physicalDevice.enumerateDeviceExtensionProperties()};
// auto features{physicalDevice.getFeatures()}; // Same as above quirks = QuirkManager(properties, features, extensions);
constexpr std::array<const char *, 1> requiredDeviceExtensions{ constexpr std::array<const char *, 1> requiredDeviceExtensions{
VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_EXTENSION_NAME,
}; };
auto deviceExtensions{physicalDevice.enumerateDeviceExtensionProperties()};
for (const auto &requiredExtension : requiredDeviceExtensions) { for (const auto &requiredExtension : requiredDeviceExtensions) {
if (!std::any_of(deviceExtensions.begin(), deviceExtensions.end(), [&](const vk::ExtensionProperties &deviceExtension) { if (!std::any_of(extensions.begin(), extensions.end(), [&](const vk::ExtensionProperties &deviceExtension) {
return std::string_view(deviceExtension.extensionName) == std::string_view(requiredExtension); return std::string_view(deviceExtension.extensionName) == std::string_view(requiredExtension);
})) }))
throw exception("Cannot find Vulkan device extension: \"{}\"", requiredExtension); throw exception("Cannot find Vulkan device extension: \"{}\"", requiredExtension);
@ -155,7 +156,7 @@ namespace skyline::gpu {
if (Logger::configLevel >= Logger::LogLevel::Info) { if (Logger::configLevel >= Logger::LogLevel::Info) {
std::string extensionString; std::string extensionString;
for (const auto &extension : deviceExtensions) for (const auto &extension : extensions)
extensionString += util::Format("\n* {} (v{}.{}.{})", extension.extensionName, VK_VERSION_MAJOR(extension.specVersion), VK_VERSION_MINOR(extension.specVersion), VK_VERSION_PATCH(extension.specVersion)); extensionString += util::Format("\n* {} (v{}.{}.{})", extension.extensionName, VK_VERSION_MAJOR(extension.specVersion), VK_VERSION_MINOR(extension.specVersion), VK_VERSION_PATCH(extension.specVersion));
std::string queueString; std::string queueString;
@ -174,5 +175,5 @@ namespace skyline::gpu {
}); });
} }
GPU::GPU(const DeviceState &state) : vkInstance(CreateInstance(state, vkContext)), vkDebugReportCallback(CreateDebugReportCallback(vkInstance)), vkPhysicalDevice(CreatePhysicalDevice(vkInstance)), vkDevice(CreateDevice(vkPhysicalDevice, vkQueueFamilyIndex)), vkQueue(vkDevice, vkQueueFamilyIndex, 0), memory(*this), scheduler(*this), presentation(state, *this), texture(*this) {} GPU::GPU(const DeviceState &state) : vkInstance(CreateInstance(state, vkContext)), vkDebugReportCallback(CreateDebugReportCallback(vkInstance)), vkPhysicalDevice(CreatePhysicalDevice(vkInstance)), vkDevice(CreateDevice(vkPhysicalDevice, vkQueueFamilyIndex, quirks)), vkQueue(vkDevice, vkQueueFamilyIndex, 0), memory(*this), scheduler(*this), presentation(state, *this), texture(*this) {}
} }

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "gpu/quirk_manager.h"
#include "gpu/memory_manager.h" #include "gpu/memory_manager.h"
#include "gpu/command_scheduler.h" #include "gpu/command_scheduler.h"
#include "gpu/presentation_engine.h" #include "gpu/presentation_engine.h"
@ -22,7 +23,7 @@ namespace skyline::gpu {
static vk::raii::PhysicalDevice CreatePhysicalDevice(const vk::raii::Instance &instance); static vk::raii::PhysicalDevice CreatePhysicalDevice(const vk::raii::Instance &instance);
static vk::raii::Device CreateDevice(const vk::raii::PhysicalDevice &physicalDevice, typeof(vk::DeviceQueueCreateInfo::queueCount)& queueConfiguration); static vk::raii::Device CreateDevice(const vk::raii::PhysicalDevice &physicalDevice, typeof(vk::DeviceQueueCreateInfo::queueCount)& queueConfiguration, QuirkManager& quirks);
public: public:
static constexpr u32 VkApiVersion{VK_API_VERSION_1_1}; //!< The version of core Vulkan that we require static constexpr u32 VkApiVersion{VK_API_VERSION_1_1}; //!< The version of core Vulkan that we require
@ -36,6 +37,8 @@ namespace skyline::gpu {
std::mutex queueMutex; //!< Synchronizes access to the queue as it is externally synchronized std::mutex queueMutex; //!< Synchronizes access to the queue as it is externally synchronized
vk::raii::Queue vkQueue; //!< A Vulkan Queue supporting graphics and compute operations vk::raii::Queue vkQueue; //!< A Vulkan Queue supporting graphics and compute operations
QuirkManager quirks;
memory::MemoryManager memory; memory::MemoryManager memory;
CommandScheduler scheduler; CommandScheduler scheduler;
PresentationEngine presentation; PresentationEngine presentation;

View File

@ -68,7 +68,6 @@ namespace skyline::gpu::memory {
.vulkanApiVersion = GPU::VkApiVersion, .vulkanApiVersion = GPU::VkApiVersion,
}; };
ThrowOnFail(vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator)); ThrowOnFail(vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator));
// TODO: Use VK_KHR_dedicated_allocation when available (Should be on Adreno GPUs)
} }
MemoryManager::~MemoryManager() { MemoryManager::~MemoryManager() {

View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include "quirk_manager.h"
namespace skyline {
QuirkManager::QuirkManager(vk::PhysicalDeviceProperties properties, vk::PhysicalDeviceFeatures2 features, const std::vector<vk::ExtensionProperties> &extensions) {
for (auto &extension : extensions) {
#define EXT_SET(name, property) \
case util::Hash(name): \
if (name == extensionName) \
property = true; \
break
#define EXT_SET_V(name, property, version) \
case util::Hash(name): \
if (name == extensionName && extensionVersion >= version) \
property = true; \
break
std::string_view extensionName{extension.extensionName};
auto extensionVersion{extension.specVersion};
switch (util::Hash(extensionName)) {
EXT_SET("VK_EXT_provoking_vertex", supportsLastProvokingVertex);
}
#undef EXT_SET
#undef EXT_SET_V
}
}
}

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <vulkan/vulkan.hpp>
#include <common.h>
namespace skyline {
/**
* @brief Checks and stores all the quirks of the host GPU discovered at runtime
*/
class QuirkManager {
public:
bool supportsLastProvokingVertex{}; //!< If the device supports setting the last vertex as the provoking vertex (with VK_EXT_provoking_vertex)
QuirkManager() = default;
QuirkManager(vk::PhysicalDeviceProperties properties, vk::PhysicalDeviceFeatures2 features, const std::vector<vk::ExtensionProperties>& extensions);
};
}