Separate Guest and Host Presentation + AChoreographer V-Sync Event

We had issues when combining host and guest presentation since certain configurations in guest presentation such as double buffering were very unoptimal for the host and would significantly affect the FPS. As a result of this, we've now made host presentation have its own presentation textures which are copied into from the guest at presentation time, allowing us to change parameters of the host presentation independently of the guest.

We've implemented the infrastructure for this which includes being able to create images from host GPU memory using VMA, an optimized linear texture sync and a method to do on-GPU texture-to-texture copies.

We've also moved to driving the V-Sync event using AChoreographer on its on thread in this PR, which more accurately encapsulates HOS behavior and allows games such as ARMS to boot as they depend on the V-Sync event being signalled even when the game isn't presenting.
This commit is contained in:
PixelyIon
2021-06-18 16:25:19 +05:30
committed by ◱ Mark
parent 36547cd5dc
commit 216e5cee81
20 changed files with 535 additions and 231 deletions

View File

@ -11,16 +11,57 @@ namespace skyline::gpu::memory {
* @brief A view into a CPU mapping of a Vulkan buffer
* @note The mapping **should not** be used after the lifetime of the object has ended
*/
struct StagingBuffer : public span<u8>, FenceCycleDependency {
struct StagingBuffer : public span<u8>, public FenceCycleDependency {
VmaAllocator vmaAllocator;
VmaAllocation vmaAllocation;
vk::Buffer vkBuffer;
constexpr StagingBuffer(u8 *pointer, size_t size, VmaAllocator vmaAllocator, vk::Buffer vkBuffer, VmaAllocation vmaAllocation) : vmaAllocator(vmaAllocator), vkBuffer(vkBuffer), vmaAllocation(vmaAllocation), span(pointer, size) {}
StagingBuffer(const StagingBuffer &) = delete;
constexpr StagingBuffer(StagingBuffer &&other) : vmaAllocator(std::exchange(other.vmaAllocator, nullptr)), vmaAllocation(std::exchange(other.vmaAllocation, nullptr)), vkBuffer(std::exchange(other.vkBuffer, {})) {}
StagingBuffer &operator=(const StagingBuffer &) = delete;
StagingBuffer &operator=(StagingBuffer &&) = default;
~StagingBuffer();
};
/**
* @brief A Vulkan image which VMA allocates and manages the backing memory for
*/
struct Image {
private:
u8 *pointer{};
public:
VmaAllocator vmaAllocator;
VmaAllocation vmaAllocation;
vk::Image vkImage;
constexpr Image(VmaAllocator vmaAllocator, vk::Image vkImage, VmaAllocation vmaAllocation) : vmaAllocator(vmaAllocator), vkImage(vkImage), vmaAllocation(vmaAllocation) {}
constexpr Image(u8 *pointer, VmaAllocator vmaAllocator, vk::Image vkImage, VmaAllocation vmaAllocation) : pointer(pointer), vmaAllocator(vmaAllocator), vkImage(vkImage), vmaAllocation(vmaAllocation) {}
Image(const Image &) = delete;
constexpr Image(Image &&other) : pointer(std::exchange(other.pointer, nullptr)), vmaAllocator(std::exchange(other.vmaAllocator, nullptr)), vmaAllocation(std::exchange(other.vmaAllocation, nullptr)), vkImage(std::exchange(other.vkImage, {})) {}
Image &operator=(const Image &) = delete;
Image &operator=(Image &&) = default;
~Image();
/**
* @return A pointer to a mapping of the image on the CPU
* @note If the image isn't already mapped on the CPU, this creates a mapping for it
*/
u8 *data();
};
/**
* @brief An abstraction over memory operations done in Vulkan, it's used for all allocations on the host GPU
*/
@ -29,11 +70,6 @@ namespace skyline::gpu::memory {
const GPU &gpu;
VmaAllocator vmaAllocator{VK_NULL_HANDLE};
/**
* @brief If the result isn't VK_SUCCESS then an exception is thrown
*/
static void ThrowOnFail(VkResult result, const char *function = __builtin_FUNCTION());
public:
MemoryManager(const GPU &gpu);
@ -43,5 +79,15 @@ namespace skyline::gpu::memory {
* @brief Creates a buffer which is optimized for staging (Transfer Source)
*/
std::shared_ptr<StagingBuffer> AllocateStagingBuffer(vk::DeviceSize size);
/**
* @brief Creates an image which is allocated and deallocated using RAII
*/
Image AllocateImage(const vk::ImageCreateInfo &createInfo);
/**
* @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);
};
}