mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 08:31:48 +01: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,
|
||||
const vk::raii::PhysicalDevice &physicalDevice,
|
||||
decltype(vk::DeviceQueueCreateInfo::queueCount) &vkQueueFamilyIndex,
|
||||
TraitManager &traits) {
|
||||
TraitManager &traits,
|
||||
adrenotools_gpu_mapping *mapping) {
|
||||
auto deviceFeatures2{physicalDevice.getFeatures2<
|
||||
vk::PhysicalDeviceFeatures2,
|
||||
vk::PhysicalDeviceCustomBorderColorFeaturesEXT,
|
||||
@ -274,7 +275,7 @@ namespace skyline::gpu {
|
||||
vk::PhysicalDeviceSubgroupProperties>()};
|
||||
|
||||
traits = TraitManager{deviceFeatures2, enabledFeatures2, deviceExtensions, enabledExtensions, deviceProperties2, physicalDevice};
|
||||
traits.ApplyDriverPatches(context);
|
||||
traits.ApplyDriverPatches(context, mapping);
|
||||
|
||||
std::vector<const char *> pEnabledExtensions;
|
||||
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{};
|
||||
|
||||
// If the user has selected a custom driver, try to load it
|
||||
if (!(*state.settings->gpuDriver).empty()) {
|
||||
libvulkanHandle = adrenotools_open_libvulkan(
|
||||
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
|
||||
state.os->nativeLibraryPath.c_str(),
|
||||
(state.os->privateAppFilesPath + "gpu_drivers/" + *state.settings->gpuDriver + "/").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) {
|
||||
@ -356,19 +358,37 @@ namespace skyline::gpu {
|
||||
}
|
||||
}
|
||||
|
||||
if (!libvulkanHandle)
|
||||
libvulkanHandle = dlopen("libvulkan.so", RTLD_NOW);
|
||||
if (!libvulkanHandle) {
|
||||
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"));
|
||||
}
|
||||
|
||||
GPU::GPU(const DeviceState &state)
|
||||
: state(state),
|
||||
vkContext(LoadVulkanDriver(state)),
|
||||
vkContext(LoadVulkanDriver(state, &adrenotoolsImportMapping)),
|
||||
vkInstance(CreateInstance(state, vkContext)),
|
||||
vkDebugReportCallback(CreateDebugReportCallback(this, vkInstance)),
|
||||
vkPhysicalDevice(CreatePhysicalDevice(vkInstance)),
|
||||
vkDevice(CreateDevice(vkContext, vkPhysicalDevice, vkQueueFamilyIndex, traits)),
|
||||
vkDevice(CreateDevice(vkContext, vkPhysicalDevice, vkQueueFamilyIndex, traits, &adrenotoolsImportMapping)),
|
||||
vkQueue(vkDevice, vkQueueFamilyIndex, 0),
|
||||
memory(*this),
|
||||
scheduler(state, *this),
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <adrenotools/driver.h>
|
||||
#include "gpu/trait_manager.h"
|
||||
#include "gpu/memory_manager.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
|
||||
friend Texture;
|
||||
friend Buffer;
|
||||
friend BufferManager;
|
||||
|
||||
public:
|
||||
adrenotools_gpu_mapping adrenotoolsImportMapping{}; //!< Persistent struct to store active adrenotools mapping import info
|
||||
vk::raii::Context vkContext;
|
||||
vk::raii::Instance vkInstance;
|
||||
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;
|
||||
}
|
||||
|
||||
MemoryManager::MemoryManager(const GPU &pGpu) : gpu(pGpu) {
|
||||
MemoryManager::MemoryManager(GPU &pGpu) : gpu{pGpu} {
|
||||
auto instanceDispatcher{gpu.vkInstance.getDispatcher()};
|
||||
auto deviceDispatcher{gpu.vkDevice.getDispatcher()};
|
||||
VmaVulkanFunctions vulkanFunctions{
|
||||
@ -143,4 +143,34 @@ namespace skyline::gpu::memory {
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @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 {
|
||||
private:
|
||||
const GPU &gpu;
|
||||
GPU &gpu;
|
||||
VmaAllocator vmaAllocator{VK_NULL_HANDLE};
|
||||
|
||||
public:
|
||||
MemoryManager(const GPU &gpu);
|
||||
MemoryManager(GPU &gpu);
|
||||
|
||||
~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
|
||||
*/
|
||||
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[5] = isFormatSupported(vk::Format::eBc6HSfloatBlock) && isFormatSupported(vk::Format::eBc6HUfloatBlock);
|
||||
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() {
|
||||
@ -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
|
||||
vk::ApplicationInfo applicationInfo{
|
||||
.apiVersion = VK_API_VERSION_1_0,
|
||||
@ -294,5 +300,10 @@ namespace skyline::gpu {
|
||||
Logger::Info("BCeNabler skipped, blob BCN support is present");
|
||||
bcnSupport.set();
|
||||
}
|
||||
|
||||
if (adrenotools_validate_gpu_mapping(mapping)) {
|
||||
Logger::Info("Applied GPU memory import patch");
|
||||
supportsAdrenoDirectMemoryImport = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
#include <adrenotools/driver.h>
|
||||
#include <common.h>
|
||||
|
||||
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 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 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
|
||||
bool supportsAdrenoDirectMemoryImport{};
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user