Skip to content

Commit

Permalink
Separate Guest and Host Presentation + AChoreographer V-Sync Event
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
PixelyIon committed Jul 12, 2021
1 parent 36547cd commit 216e5ce
Show file tree
Hide file tree
Showing 20 changed files with 536 additions and 232 deletions.
13 changes: 1 addition & 12 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/scopes/SkylineLibraries.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions app/src/main/cpp/skyline/common/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ namespace skyline {
#define PREF_ELEM(name, memberName, rhs) std::make_pair(std::string(name), [](Settings &settings, const pugi::xml_node &element) { settings.memberName = rhs; })

std::tuple preferences{
PREF_ELEM("operation_mode", operationMode, element.attribute("value").as_bool()),
PREF_ELEM("username_value", username, element.text().as_string()),
PREF_ELEM("log_level", logLevel, static_cast<Logger::LogLevel>(element.text().as_uint(static_cast<unsigned int>(Logger::LogLevel::Info)))),
PREF_ELEM("username_value", username, element.text().as_string()),
PREF_ELEM("operation_mode", operationMode, element.attribute("value").as_bool()),
};

#undef PREF_ELEM
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/cpp/skyline/common/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ namespace skyline {
class Settings {
public:
Logger::LogLevel logLevel; //!< The minimum level that logs need to be for them to be printed
bool operationMode; //!< If the emulated Switch should be handheld or docked
std::string username; //!< The name set by the user to be supplied to the guest
bool operationMode; //!< If the emulated Switch should be handheld or docked
bool forceTripleBuffering{true}; //!< If the presentation should always triple buffer even if the game double buffers

/**
* @param fd An FD to the preference XML file
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/cpp/skyline/gpu/fence_cycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ namespace skyline::gpu {
}
}

const auto& first{*dependencies.begin()};
const auto& last{*dependencies.end()};
const auto &first{*dependencies.begin()};
const auto &last{*dependencies.end()};
std::shared_ptr<FenceCycleDependency> next{std::atomic_load_explicit(&list, std::memory_order_consume)};
do {
last->next = next;
Expand Down
53 changes: 50 additions & 3 deletions app/src/main/cpp/skyline/gpu/memory_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,32 @@
#include "memory_manager.h"

namespace skyline::gpu::memory {
/**
* @brief If the result isn't VK_SUCCESS then an exception is thrown
*/
void ThrowOnFail(VkResult result, const char *function = __builtin_FUNCTION()) {
if (result != VK_SUCCESS)
vk::throwResultException(vk::Result(result), function);
}

StagingBuffer::~StagingBuffer() {
if (vmaAllocator && vmaAllocation && vkBuffer)
vmaDestroyBuffer(vmaAllocator, vkBuffer, vmaAllocation);
}

void MemoryManager::ThrowOnFail(VkResult result, const char *function) {
if (result != VK_SUCCESS)
vk::throwResultException(vk::Result(result), function);
Image::~Image() {
if (vmaAllocator && vmaAllocation && vkImage) {
if (pointer)
vmaUnmapMemory(vmaAllocator, vmaAllocation);
vmaDestroyImage(vmaAllocator, vkImage, vmaAllocation);
}
}

u8 *Image::data() {
if (pointer) [[likely]]
return pointer;
ThrowOnFail(vmaMapMemory(vmaAllocator, vmaAllocation, reinterpret_cast<void **>(&pointer)));
return pointer;
}

MemoryManager::MemoryManager(const GPU &pGpu) : gpu(pGpu) {
Expand Down Expand Up @@ -75,4 +94,32 @@ namespace skyline::gpu::memory {

return std::make_shared<memory::StagingBuffer>(reinterpret_cast<u8 *>(allocationInfo.pMappedData), allocationInfo.size, vmaAllocator, buffer, allocation);
}

Image MemoryManager::AllocateImage(const vk::ImageCreateInfo &createInfo) {
VmaAllocationCreateInfo allocationCreateInfo{
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
};

VkImage image;
VmaAllocation allocation;
VmaAllocationInfo allocationInfo;
ThrowOnFail(vmaCreateImage(vmaAllocator, &static_cast<const VkImageCreateInfo &>(createInfo), &allocationCreateInfo, &image, &allocation, &allocationInfo));

return Image(vmaAllocator, image, allocation);
}

Image MemoryManager::AllocateMappedImage(const vk::ImageCreateInfo &createInfo) {
VmaAllocationCreateInfo allocationCreateInfo{
.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT,
.usage = VMA_MEMORY_USAGE_UNKNOWN,
.memoryTypeBits = static_cast<u32>(vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eDeviceLocal),
};

VkImage image;
VmaAllocation allocation;
VmaAllocationInfo allocationInfo;
ThrowOnFail(vmaCreateImage(vmaAllocator, &static_cast<const VkImageCreateInfo &>(createInfo), &allocationCreateInfo, &image, &allocation, &allocationInfo));

return Image(reinterpret_cast<u8 *>(allocationInfo.pMappedData), vmaAllocator, image, allocation);
}
}
Loading

0 comments on commit 216e5ce

Please sign in to comment.