mirror of
https://github.com/Takiiiiiiii/strato.git
synced 2025-07-17 08:46:39 +00:00
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:
@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/looper.h>
|
||||
#include <common/trace.h>
|
||||
#include <kernel/types/KEvent.h>
|
||||
#include <services/hosbinder/GraphicBufferProducer.h>
|
||||
@ -27,31 +28,31 @@ namespace skyline::gpu {
|
||||
vk::SurfaceCapabilitiesKHR vkSurfaceCapabilities; //!< The capabilities of the current Vulkan Surface
|
||||
|
||||
std::optional<vk::raii::SwapchainKHR> vkSwapchain; //!< The Vulkan swapchain and the properties associated with it
|
||||
struct SwapchainContext {
|
||||
std::array<std::shared_ptr<Texture>, service::hosbinder::GraphicBufferProducer::MaxSlotCount> textures{};
|
||||
std::array<VkImage, service::hosbinder::GraphicBufferProducer::MaxSlotCount> vkImages{VK_NULL_HANDLE};
|
||||
u8 imageCount{};
|
||||
i8 dequeuedCount{};
|
||||
vk::Format imageFormat{};
|
||||
vk::Extent2D imageExtent{};
|
||||
vk::raii::Fence acquireFence; //!< A fence for acquiring an image from the swapchain
|
||||
texture::Format swapchainFormat{}; //!< The image format of the textures in the current swapchain
|
||||
texture::Dimensions swapchainExtent{}; //!< The extent of images in the current swapchain
|
||||
|
||||
static_assert(std::numeric_limits<decltype(imageCount)>::max() >= service::hosbinder::GraphicBufferProducer::MaxSlotCount);
|
||||
static_assert(std::numeric_limits<decltype(dequeuedCount)>::max() >= service::hosbinder::GraphicBufferProducer::MaxSlotCount);
|
||||
} swapchain; //!< The properties of the currently created swapchain
|
||||
static constexpr size_t MaxSlotCount{6}; //!< The maximum amount of queue slots, this affects the amount of images that can be in the swapchain
|
||||
std::array<std::shared_ptr<Texture>, MaxSlotCount> slots; //!< The backing for storing all slots and sorted in the same order as supplied by the Vulkan swapchain
|
||||
|
||||
u64 frameTimestamp{}; //!< The timestamp of the last frame being shown
|
||||
perfetto::Track presentationTrack; //!< Perfetto track used for presentation events
|
||||
|
||||
std::thread choreographerThread; //!< A thread for signalling the V-Sync event using AChoreographer
|
||||
ALooper* choreographerLooper{}; //!< The looper object associated with the Choreographer thread
|
||||
|
||||
/**
|
||||
* @brief The entry point for the the Choreographer thread, the function runs ALooper on the thread
|
||||
*/
|
||||
void ChoreographerThread();
|
||||
|
||||
/**
|
||||
* @note 'PresentationEngine::mutex' **must** be locked prior to calling this
|
||||
*/
|
||||
void UpdateSwapchain(u16 imageCount, vk::Format imageFormat, vk::Extent2D imageExtent, bool newSurface = false);
|
||||
void UpdateSwapchain(texture::Format format, texture::Dimensions extent);
|
||||
|
||||
public:
|
||||
texture::Dimensions resolution{};
|
||||
i32 format{};
|
||||
std::shared_ptr<kernel::type::KEvent> vsyncEvent; //!< Signalled every time a frame is drawn
|
||||
std::shared_ptr<kernel::type::KEvent> bufferEvent; //!< Signalled every time a buffer is freed
|
||||
|
||||
PresentationEngine(const DeviceState &state, GPU &gpu);
|
||||
|
||||
@ -63,20 +64,11 @@ namespace skyline::gpu {
|
||||
void UpdateSurface(jobject newSurface);
|
||||
|
||||
/**
|
||||
* @brief Creates a Texture object from a GuestTexture as a part of the Vulkan swapchain
|
||||
* @brief Queue the supplied texture to be presented to the screen
|
||||
* @param presentId A UUID used to tag this frame for presentation timing readouts
|
||||
* @note The texture **must** be locked prior to calling this
|
||||
*/
|
||||
std::shared_ptr<Texture> CreatePresentationTexture(const std::shared_ptr<GuestTexture> &texture, u8 slot);
|
||||
|
||||
/**
|
||||
* @param async If to return immediately when a texture is not available
|
||||
* @param slot The slot the freed texture is in is written into this, it is untouched if there's an error
|
||||
*/
|
||||
service::hosbinder::AndroidStatus GetFreeTexture(bool async, i32 &slot);
|
||||
|
||||
/**
|
||||
* @brief Send a texture from a slot to the presentation queue to be displayed
|
||||
*/
|
||||
void Present(u32 slot);
|
||||
void Present(const std::shared_ptr<Texture> &texture, u64 presentId);
|
||||
|
||||
/**
|
||||
* @return A transform that the application should render with to elide costly transforms later
|
||||
|
Reference in New Issue
Block a user