mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 22:35:29 +03:00
Add adrenotools direct mapping support
This commit is contained in:
parent
8846a85d3a
commit
3ecaedd71e
@ -219,7 +219,8 @@ namespace skyline::gpu {
|
|||||||
static vk::raii::Device CreateDevice(const vk::raii::Context &context,
|
static vk::raii::Device CreateDevice(const vk::raii::Context &context,
|
||||||
const vk::raii::PhysicalDevice &physicalDevice,
|
const vk::raii::PhysicalDevice &physicalDevice,
|
||||||
decltype(vk::DeviceQueueCreateInfo::queueCount) &vkQueueFamilyIndex,
|
decltype(vk::DeviceQueueCreateInfo::queueCount) &vkQueueFamilyIndex,
|
||||||
TraitManager &traits) {
|
TraitManager &traits,
|
||||||
|
adrenotools_gpu_mapping *mapping) {
|
||||||
auto deviceFeatures2{physicalDevice.getFeatures2<
|
auto deviceFeatures2{physicalDevice.getFeatures2<
|
||||||
vk::PhysicalDeviceFeatures2,
|
vk::PhysicalDeviceFeatures2,
|
||||||
vk::PhysicalDeviceCustomBorderColorFeaturesEXT,
|
vk::PhysicalDeviceCustomBorderColorFeaturesEXT,
|
||||||
@ -274,7 +275,7 @@ namespace skyline::gpu {
|
|||||||
vk::PhysicalDeviceSubgroupProperties>()};
|
vk::PhysicalDeviceSubgroupProperties>()};
|
||||||
|
|
||||||
traits = TraitManager{deviceFeatures2, enabledFeatures2, deviceExtensions, enabledExtensions, deviceProperties2, physicalDevice};
|
traits = TraitManager{deviceFeatures2, enabledFeatures2, deviceExtensions, enabledExtensions, deviceProperties2, physicalDevice};
|
||||||
traits.ApplyDriverPatches(context);
|
traits.ApplyDriverPatches(context, mapping);
|
||||||
|
|
||||||
std::vector<const char *> pEnabledExtensions;
|
std::vector<const char *> pEnabledExtensions;
|
||||||
pEnabledExtensions.reserve(enabledExtensions.size());
|
pEnabledExtensions.reserve(enabledExtensions.size());
|
||||||
@ -335,19 +336,20 @@ namespace skyline::gpu {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static PFN_vkGetInstanceProcAddr LoadVulkanDriver(const DeviceState &state) {
|
static PFN_vkGetInstanceProcAddr LoadVulkanDriver(const DeviceState &state, adrenotools_gpu_mapping *mapping) {
|
||||||
void *libvulkanHandle{};
|
void *libvulkanHandle{};
|
||||||
|
|
||||||
// If the user has selected a custom driver, try to load it
|
// If the user has selected a custom driver, try to load it
|
||||||
if (!(*state.settings->gpuDriver).empty()) {
|
if (!(*state.settings->gpuDriver).empty()) {
|
||||||
libvulkanHandle = adrenotools_open_libvulkan(
|
libvulkanHandle = adrenotools_open_libvulkan(
|
||||||
RTLD_NOW,
|
RTLD_NOW,
|
||||||
ADRENOTOOLS_DRIVER_FILE_REDIRECT | ADRENOTOOLS_DRIVER_CUSTOM,
|
ADRENOTOOLS_DRIVER_FILE_REDIRECT | ADRENOTOOLS_DRIVER_CUSTOM | ADRENOTOOLS_DRIVER_GPU_MAPPING_IMPORT,
|
||||||
nullptr, // We require Android 10 so don't need to supply
|
nullptr, // We require Android 10 so don't need to supply
|
||||||
state.os->nativeLibraryPath.c_str(),
|
state.os->nativeLibraryPath.c_str(),
|
||||||
(state.os->privateAppFilesPath + "gpu_drivers/" + *state.settings->gpuDriver + "/").c_str(),
|
(state.os->privateAppFilesPath + "gpu_drivers/" + *state.settings->gpuDriver + "/").c_str(),
|
||||||
(*state.settings->gpuDriverLibraryName).c_str(),
|
(*state.settings->gpuDriverLibraryName).c_str(),
|
||||||
(state.os->publicAppFilesPath + "gpu/vk_file_redirect/").c_str()
|
(state.os->publicAppFilesPath + "gpu/vk_file_redirect/").c_str(),
|
||||||
|
mapping
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!libvulkanHandle) {
|
if (!libvulkanHandle) {
|
||||||
@ -356,19 +358,37 @@ namespace skyline::gpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!libvulkanHandle)
|
if (!libvulkanHandle) {
|
||||||
libvulkanHandle = dlopen("libvulkan.so", RTLD_NOW);
|
libvulkanHandle = adrenotools_open_libvulkan(
|
||||||
|
RTLD_NOW,
|
||||||
|
ADRENOTOOLS_DRIVER_FILE_REDIRECT | ADRENOTOOLS_DRIVER_GPU_MAPPING_IMPORT,
|
||||||
|
nullptr, // We require Android 10 so don't need to supply
|
||||||
|
state.os->nativeLibraryPath.c_str(),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
(state.os->publicAppFilesPath + "gpu/vk_file_redirect/").c_str(),
|
||||||
|
mapping
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!libvulkanHandle) {
|
||||||
|
char *error = dlerror();
|
||||||
|
Logger::Warn("Failed to load builtin Vulkan driver: {}", error ? error : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!libvulkanHandle)
|
||||||
|
libvulkanHandle = dlopen("libvulkan.so", RTLD_NOW);
|
||||||
|
}
|
||||||
|
|
||||||
return reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(libvulkanHandle, "vkGetInstanceProcAddr"));
|
return reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(libvulkanHandle, "vkGetInstanceProcAddr"));
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU::GPU(const DeviceState &state)
|
GPU::GPU(const DeviceState &state)
|
||||||
: state(state),
|
: state(state),
|
||||||
vkContext(LoadVulkanDriver(state)),
|
vkContext(LoadVulkanDriver(state, &adrenotoolsImportMapping)),
|
||||||
vkInstance(CreateInstance(state, vkContext)),
|
vkInstance(CreateInstance(state, vkContext)),
|
||||||
vkDebugReportCallback(CreateDebugReportCallback(this, vkInstance)),
|
vkDebugReportCallback(CreateDebugReportCallback(this, vkInstance)),
|
||||||
vkPhysicalDevice(CreatePhysicalDevice(vkInstance)),
|
vkPhysicalDevice(CreatePhysicalDevice(vkInstance)),
|
||||||
vkDevice(CreateDevice(vkContext, vkPhysicalDevice, vkQueueFamilyIndex, traits)),
|
vkDevice(CreateDevice(vkContext, vkPhysicalDevice, vkQueueFamilyIndex, traits, &adrenotoolsImportMapping)),
|
||||||
vkQueue(vkDevice, vkQueueFamilyIndex, 0),
|
vkQueue(vkDevice, vkQueueFamilyIndex, 0),
|
||||||
memory(*this),
|
memory(*this),
|
||||||
scheduler(state, *this),
|
scheduler(state, *this),
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <adrenotools/driver.h>
|
||||||
#include "gpu/trait_manager.h"
|
#include "gpu/trait_manager.h"
|
||||||
#include "gpu/memory_manager.h"
|
#include "gpu/memory_manager.h"
|
||||||
#include "gpu/command_scheduler.h"
|
#include "gpu/command_scheduler.h"
|
||||||
@ -31,8 +32,10 @@ namespace skyline::gpu {
|
|||||||
const DeviceState &state; // We access the device state inside Texture (and Buffers) for setting up NCE memory tracking
|
const DeviceState &state; // We access the device state inside Texture (and Buffers) for setting up NCE memory tracking
|
||||||
friend Texture;
|
friend Texture;
|
||||||
friend Buffer;
|
friend Buffer;
|
||||||
|
friend BufferManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
adrenotools_gpu_mapping adrenotoolsImportMapping{}; //!< Persistent struct to store active adrenotools mapping import info
|
||||||
vk::raii::Context vkContext;
|
vk::raii::Context vkContext;
|
||||||
vk::raii::Instance vkInstance;
|
vk::raii::Instance vkInstance;
|
||||||
vk::raii::DebugReportCallbackEXT vkDebugReportCallback; //!< An RAII Vulkan debug report manager which calls into 'GPU::DebugCallback'
|
vk::raii::DebugReportCallbackEXT vkDebugReportCallback; //!< An RAII Vulkan debug report manager which calls into 'GPU::DebugCallback'
|
||||||
|
@ -33,7 +33,7 @@ namespace skyline::gpu::memory {
|
|||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryManager::MemoryManager(const GPU &pGpu) : gpu(pGpu) {
|
MemoryManager::MemoryManager(GPU &pGpu) : gpu{pGpu} {
|
||||||
auto instanceDispatcher{gpu.vkInstance.getDispatcher()};
|
auto instanceDispatcher{gpu.vkInstance.getDispatcher()};
|
||||||
auto deviceDispatcher{gpu.vkDevice.getDispatcher()};
|
auto deviceDispatcher{gpu.vkDevice.getDispatcher()};
|
||||||
VmaVulkanFunctions vulkanFunctions{
|
VmaVulkanFunctions vulkanFunctions{
|
||||||
@ -143,4 +143,34 @@ namespace skyline::gpu::memory {
|
|||||||
|
|
||||||
return Image(vmaAllocator, image, allocation);
|
return Image(vmaAllocator, image, allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImportedBuffer MemoryManager::ImportBuffer(span<u8> cpuMapping) {
|
||||||
|
if (!gpu.traits.supportsAdrenoDirectMemoryImport)
|
||||||
|
throw exception("Cannot import host buffers without adrenotools import support!");
|
||||||
|
|
||||||
|
if (!adrenotools_import_user_mem(&gpu.adrenotoolsImportMapping, cpuMapping.data(), cpuMapping.size()))
|
||||||
|
throw exception("Failed to import user memory");
|
||||||
|
|
||||||
|
auto buffer{gpu.vkDevice.createBuffer(vk::BufferCreateInfo{
|
||||||
|
.size = cpuMapping.size(),
|
||||||
|
.usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eUniformTexelBuffer | vk::BufferUsageFlagBits::eStorageTexelBuffer | vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndirectBuffer | vk::BufferUsageFlagBits::eTransformFeedbackBufferEXT,
|
||||||
|
.sharingMode = vk::SharingMode::eExclusive
|
||||||
|
})};
|
||||||
|
|
||||||
|
auto memory{gpu.vkDevice.allocateMemory(vk::MemoryAllocateInfo{
|
||||||
|
.allocationSize = cpuMapping.size(),
|
||||||
|
.memoryTypeIndex = gpu.traits.hostVisibleCoherentCachedMemoryType,
|
||||||
|
})};
|
||||||
|
|
||||||
|
if (!adrenotools_validate_gpu_mapping(&gpu.adrenotoolsImportMapping))
|
||||||
|
throw exception("Failed to validate GPU mapping");
|
||||||
|
|
||||||
|
gpu.vkDevice.bindBufferMemory2({vk::BindBufferMemoryInfo{
|
||||||
|
.buffer = *buffer,
|
||||||
|
.memory = *memory,
|
||||||
|
.memoryOffset = 0
|
||||||
|
}});
|
||||||
|
|
||||||
|
return ImportedBuffer{cpuMapping, std::move(buffer), std::move(memory)};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,30 @@ namespace skyline::gpu::memory {
|
|||||||
using Buffer::Buffer;
|
using Buffer::Buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A buffer that directly owns it's own memory
|
||||||
|
*/
|
||||||
|
struct ImportedBuffer : public span<u8> {
|
||||||
|
vk::raii::Buffer vkBuffer;
|
||||||
|
vk::raii::DeviceMemory vkMemory;
|
||||||
|
|
||||||
|
ImportedBuffer(span<u8> data, vk::raii::Buffer vkBuffer, vk::raii::DeviceMemory vkMemory)
|
||||||
|
: vkBuffer{std::move(vkBuffer)},
|
||||||
|
vkMemory{std::move(vkMemory)},
|
||||||
|
span{data} {}
|
||||||
|
|
||||||
|
ImportedBuffer(const ImportedBuffer &) = delete;
|
||||||
|
|
||||||
|
ImportedBuffer(ImportedBuffer &&other)
|
||||||
|
: vkBuffer{std::move(other.vkBuffer)},
|
||||||
|
vkMemory{std::move(other.vkMemory)},
|
||||||
|
span{other} {}
|
||||||
|
|
||||||
|
ImportedBuffer &operator=(const ImportedBuffer &) = delete;
|
||||||
|
|
||||||
|
ImportedBuffer &operator=(ImportedBuffer &&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A Vulkan image which VMA allocates and manages the backing memory for
|
* @brief A Vulkan image which VMA allocates and manages the backing memory for
|
||||||
* @note Any images created with VMA_ALLOCATION_CREATE_MAPPED_BIT must not be utilized with this since it'll unconditionally unmap when a pointer is present which is illegal when an image was created with that flag as unmapping will be automatically performed on image deletion
|
* @note Any images created with VMA_ALLOCATION_CREATE_MAPPED_BIT must not be utilized with this since it'll unconditionally unmap when a pointer is present which is illegal when an image was created with that flag as unmapping will be automatically performed on image deletion
|
||||||
@ -94,11 +118,11 @@ namespace skyline::gpu::memory {
|
|||||||
*/
|
*/
|
||||||
class MemoryManager {
|
class MemoryManager {
|
||||||
private:
|
private:
|
||||||
const GPU &gpu;
|
GPU &gpu;
|
||||||
VmaAllocator vmaAllocator{VK_NULL_HANDLE};
|
VmaAllocator vmaAllocator{VK_NULL_HANDLE};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MemoryManager(const GPU &gpu);
|
MemoryManager(GPU &gpu);
|
||||||
|
|
||||||
~MemoryManager();
|
~MemoryManager();
|
||||||
|
|
||||||
@ -121,5 +145,10 @@ namespace skyline::gpu::memory {
|
|||||||
* @brief Creates an image which is allocated and deallocated using RAII and is optimal for being mapped on the CPU
|
* @brief Creates an image which is allocated and deallocated using RAII and is optimal for being mapped on the CPU
|
||||||
*/
|
*/
|
||||||
Image AllocateMappedImage(const vk::ImageCreateInfo &createInfo);
|
Image AllocateMappedImage(const vk::ImageCreateInfo &createInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maps the input CPU mapped region into a new buffer
|
||||||
|
*/
|
||||||
|
ImportedBuffer ImportBuffer(span<u8> cpuMapping);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,12 @@ namespace skyline::gpu {
|
|||||||
bcnSupport[4] = isFormatSupported(vk::Format::eBc5UnormBlock) && isFormatSupported(vk::Format::eBc5SnormBlock);
|
bcnSupport[4] = isFormatSupported(vk::Format::eBc5UnormBlock) && isFormatSupported(vk::Format::eBc5SnormBlock);
|
||||||
bcnSupport[5] = isFormatSupported(vk::Format::eBc6HSfloatBlock) && isFormatSupported(vk::Format::eBc6HUfloatBlock);
|
bcnSupport[5] = isFormatSupported(vk::Format::eBc6HSfloatBlock) && isFormatSupported(vk::Format::eBc6HUfloatBlock);
|
||||||
bcnSupport[6] = isFormatSupported(vk::Format::eBc7UnormBlock) && isFormatSupported(vk::Format::eBc7SrgbBlock);
|
bcnSupport[6] = isFormatSupported(vk::Format::eBc7UnormBlock) && isFormatSupported(vk::Format::eBc7SrgbBlock);
|
||||||
|
|
||||||
|
auto memoryProps{physicalDevice.getMemoryProperties2()};
|
||||||
|
constexpr auto ReqMemFlags{vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached};
|
||||||
|
for (u32 i{}; i < memoryProps.memoryProperties.memoryTypeCount; i++)
|
||||||
|
if ((memoryProps.memoryProperties.memoryTypes[i].propertyFlags & ReqMemFlags) == ReqMemFlags)
|
||||||
|
hostVisibleCoherentCachedMemoryType = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TraitManager::Summary() {
|
std::string TraitManager::Summary() {
|
||||||
@ -269,7 +275,7 @@ namespace skyline::gpu {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraitManager::ApplyDriverPatches(const vk::raii::Context &context) {
|
void TraitManager::ApplyDriverPatches(const vk::raii::Context &context, adrenotools_gpu_mapping *mapping) {
|
||||||
// Create an instance without validation layers in order to get pointers to the functions we need to patch from the driver
|
// Create an instance without validation layers in order to get pointers to the functions we need to patch from the driver
|
||||||
vk::ApplicationInfo applicationInfo{
|
vk::ApplicationInfo applicationInfo{
|
||||||
.apiVersion = VK_API_VERSION_1_0,
|
.apiVersion = VK_API_VERSION_1_0,
|
||||||
@ -294,5 +300,10 @@ namespace skyline::gpu {
|
|||||||
Logger::Info("BCeNabler skipped, blob BCN support is present");
|
Logger::Info("BCeNabler skipped, blob BCN support is present");
|
||||||
bcnSupport.set();
|
bcnSupport.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (adrenotools_validate_gpu_mapping(mapping)) {
|
||||||
|
Logger::Info("Applied GPU memory import patch");
|
||||||
|
supportsAdrenoDirectMemoryImport = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan_raii.hpp>
|
#include <vulkan/vulkan_raii.hpp>
|
||||||
|
#include <adrenotools/driver.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
namespace skyline::gpu {
|
namespace skyline::gpu {
|
||||||
@ -49,8 +50,10 @@ namespace skyline::gpu {
|
|||||||
bool supportsExtendedDynamicState{}; //!< If the device supports the 'VK_EXT_extended_dynamic_state' Vulkan extension
|
bool supportsExtendedDynamicState{}; //!< If the device supports the 'VK_EXT_extended_dynamic_state' Vulkan extension
|
||||||
bool supportsNullDescriptor{}; //!< If the device supports the null descriptor feature in the 'VK_EXT_robustness2' Vulkan extension
|
bool supportsNullDescriptor{}; //!< If the device supports the null descriptor feature in the 'VK_EXT_robustness2' Vulkan extension
|
||||||
u32 subgroupSize{}; //!< Size of a subgroup on the host GPU
|
u32 subgroupSize{}; //!< Size of a subgroup on the host GPU
|
||||||
|
u32 hostVisibleCoherentCachedMemoryType{std::numeric_limits<u32>::max()};
|
||||||
|
|
||||||
std::bitset<7> bcnSupport{}; //!< Bitmask of BCn texture formats supported, it is ordered as BC1, BC2, BC3, BC4, BC5, BC6H and BC7
|
std::bitset<7> bcnSupport{}; //!< Bitmask of BCn texture formats supported, it is ordered as BC1, BC2, BC3, BC4, BC5, BC6H and BC7
|
||||||
|
bool supportsAdrenoDirectMemoryImport{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Manages a list of any vendor/device-specific errata in the host GPU
|
* @brief Manages a list of any vendor/device-specific errata in the host GPU
|
||||||
@ -111,7 +114,7 @@ namespace skyline::gpu {
|
|||||||
/**
|
/**
|
||||||
* @brief Applies driver specific binary patches to the driver (e.g. BCeNabler)
|
* @brief Applies driver specific binary patches to the driver (e.g. BCeNabler)
|
||||||
*/
|
*/
|
||||||
void ApplyDriverPatches(const vk::raii::Context &context);
|
void ApplyDriverPatches(const vk::raii::Context &context, adrenotools_gpu_mapping *mapping);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A summary of all the GPU traits as a human-readable string
|
* @return A summary of all the GPU traits as a human-readable string
|
||||||
|
Loading…
Reference in New Issue
Block a user