mirror of
https://github.com/Takiiiiiiii/strato.git
synced 2025-07-17 08:46:39 +00:00
Revamp Host1X Syncpoint + Address Review Comments
This commit is contained in:
@ -15,7 +15,7 @@ namespace skyline::gpu::memory {
|
||||
|
||||
StagingBuffer::~StagingBuffer() {
|
||||
if (vmaAllocator && vmaAllocation && vkBuffer)
|
||||
vmaDestroyBuffer(vmaAllocator, vkBuffer, vmaAllocation);
|
||||
vmaDestroyBuffer(vmaAllocator, vkBuffer, vmaAllocation);
|
||||
}
|
||||
|
||||
Image::~Image() {
|
||||
|
@ -34,7 +34,7 @@ namespace skyline::gpu {
|
||||
/**
|
||||
* @url https://developer.android.com/ndk/reference/group/choreographer#achoreographer_framecallback
|
||||
*/
|
||||
void ChoreographerCallback(long frameTimeNanos, kernel::type::KEvent* vsyncEvent) {
|
||||
void ChoreographerCallback(long frameTimeNanos, kernel::type::KEvent *vsyncEvent) {
|
||||
vsyncEvent->Signal();
|
||||
AChoreographer_postFrameCallback(AChoreographer_getInstance(), reinterpret_cast<AChoreographer_frameCallback>(&ChoreographerCallback), vsyncEvent);
|
||||
}
|
||||
@ -42,7 +42,7 @@ namespace skyline::gpu {
|
||||
void PresentationEngine::ChoreographerThread() {
|
||||
choreographerLooper = ALooper_prepare(0);
|
||||
AChoreographer_postFrameCallback(AChoreographer_getInstance(), reinterpret_cast<AChoreographer_frameCallback>(&ChoreographerCallback), vsyncEvent.get());
|
||||
ALooper_pollAll(-1, nullptr, nullptr, nullptr);
|
||||
ALooper_pollAll(-1, nullptr, nullptr, nullptr); // Will block and process callbacks till ALooper_wake() is called
|
||||
}
|
||||
|
||||
service::hosbinder::NativeWindowTransform GetAndroidTransform(vk::SurfaceTransformFlagBitsKHR transform) {
|
||||
@ -70,8 +70,8 @@ namespace skyline::gpu {
|
||||
|
||||
void PresentationEngine::UpdateSwapchain(texture::Format format, texture::Dimensions extent) {
|
||||
auto minImageCount{std::max(vkSurfaceCapabilities.minImageCount, state.settings->forceTripleBuffering ? 3U : 0U)};
|
||||
if (minImageCount > MaxSlotCount)
|
||||
throw exception("Requesting swapchain with higher image count ({}) than maximum slot count ({})", minImageCount, MaxSlotCount);
|
||||
if (minImageCount > MaxSwapchainImageCount)
|
||||
throw exception("Requesting swapchain with higher image count ({}) than maximum slot count ({})", minImageCount, MaxSwapchainImageCount);
|
||||
|
||||
const auto &capabilities{vkSurfaceCapabilities};
|
||||
if (minImageCount < capabilities.minImageCount || (capabilities.maxImageCount && minImageCount > capabilities.maxImageCount))
|
||||
@ -104,16 +104,17 @@ namespace skyline::gpu {
|
||||
});
|
||||
|
||||
auto vkImages{vkSwapchain->getImages()};
|
||||
if (vkImages.size() > MaxSlotCount)
|
||||
throw exception("Swapchain has higher image count ({}) than maximum slot count ({})", minImageCount, MaxSlotCount);
|
||||
if (vkImages.size() > MaxSwapchainImageCount)
|
||||
throw exception("Swapchain has higher image count ({}) than maximum slot count ({})", minImageCount, MaxSwapchainImageCount);
|
||||
|
||||
for (size_t index{}; index < vkImages.size(); index++) {
|
||||
auto &slot{slots[index]};
|
||||
auto &slot{images[index]};
|
||||
slot = std::make_shared<Texture>(*state.gpu, vkImages[index], extent, format::GetFormat(format), vk::ImageLayout::eUndefined, vk::ImageTiling::eOptimal);
|
||||
slot->TransitionLayout(vk::ImageLayout::ePresentSrcKHR);
|
||||
}
|
||||
for (size_t index{vkImages.size()}; index < MaxSlotCount; index++)
|
||||
slots[index] = {};
|
||||
for (size_t index{vkImages.size()}; index < MaxSwapchainImageCount; index++)
|
||||
// We need to clear all the slots which aren't filled, keeping around stale slots could lead to issues
|
||||
images[index] = {};
|
||||
|
||||
swapchainFormat = format;
|
||||
swapchainExtent = extent;
|
||||
@ -157,14 +158,15 @@ namespace skyline::gpu {
|
||||
UpdateSwapchain(texture->format, texture->dimensions);
|
||||
|
||||
std::pair<vk::Result, u32> nextImage;
|
||||
while ((nextImage = vkSwapchain->acquireNextImage(std::numeric_limits<u64>::max(), {}, *acquireFence)).first != vk::Result::eSuccess) [[unlikely]]
|
||||
while (nextImage = vkSwapchain->acquireNextImage(std::numeric_limits<u64>::max(), {}, *acquireFence), nextImage.first != vk::Result::eSuccess) [[unlikely]] {
|
||||
if (nextImage.first == vk::Result::eSuboptimalKHR)
|
||||
surfaceCondition.wait(lock, [this]() { return vkSurface.has_value(); });
|
||||
else
|
||||
throw exception("vkAcquireNextImageKHR returned an unhandled result '{}'", vk::to_string(nextImage.first));
|
||||
while (gpu.vkDevice.waitForFences(*acquireFence, true, std::numeric_limits<u64>::max()) == vk::Result::eTimeout);
|
||||
}
|
||||
|
||||
slots.at(nextImage.second)->CopyFrom(texture);
|
||||
static_cast<void>(gpu.vkDevice.waitForFences(*acquireFence, true, std::numeric_limits<u64>::max()));
|
||||
images.at(nextImage.second)->CopyFrom(texture);
|
||||
|
||||
{
|
||||
std::lock_guard queueLock(gpu.queueMutex);
|
||||
|
@ -32,14 +32,14 @@ namespace skyline::gpu {
|
||||
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 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
|
||||
static constexpr size_t MaxSwapchainImageCount{6}; //!< The maximum amount of swapchain textures, this affects the amount of images that can be in the swapchain
|
||||
std::array<std::shared_ptr<Texture>, MaxSwapchainImageCount> images; //!< All the swapchain textures in the same order as supplied by the host 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
|
||||
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
|
||||
|
@ -12,7 +12,7 @@ namespace skyline::gpu::format {
|
||||
constexpr Format RGB565Unorm{sizeof(u8) * 2, 1, 1, vk::Format::eR5G6B5UnormPack16}; //!< Red channel: 5-bit, Green channel: 6-bit, Blue channel: 5-bit
|
||||
|
||||
/**
|
||||
* @brief Converts a format from Vulkan to a Skyline format
|
||||
* @brief Converts a Vulkan format to a Skyline format
|
||||
*/
|
||||
constexpr const Format &GetFormat(vk::Format format) {
|
||||
switch (format) {
|
||||
|
@ -140,12 +140,14 @@ namespace skyline::gpu {
|
||||
u8 *bufferData;
|
||||
auto stagingBuffer{[&]() -> std::shared_ptr<memory::StagingBuffer> {
|
||||
if (tiling == vk::ImageTiling::eOptimal || !std::holds_alternative<memory::Image>(backing)) {
|
||||
// We need a staging buffer for all optimal copies (Since we aren't aware of the host optimal layout) and linear textures which we cannot map on the CPU since we do not have access to their backing VkDeviceMemory
|
||||
auto stagingBuffer{gpu.memory.AllocateStagingBuffer(size)};
|
||||
bufferData = stagingBuffer->data();
|
||||
return stagingBuffer;
|
||||
} else if (tiling == vk::ImageTiling::eLinear) {
|
||||
// We can optimize linear texture sync on a UMA by mapping the texture onto the CPU and copying directly into it rather than a staging buffer
|
||||
bufferData = std::get<memory::Image>(backing).data();
|
||||
WaitOnFence();
|
||||
WaitOnFence(); // We need to wait on fence here since we are mutating the texture directly after, the wait can be deferred till the copy when a staging buffer is used
|
||||
return nullptr;
|
||||
} else {
|
||||
throw exception("Guest -> Host synchronization of images tiled as '{}' isn't implemented", vk::to_string(tiling));
|
||||
|
@ -188,7 +188,7 @@ namespace skyline::gpu {
|
||||
texture::TileMode tileMode;
|
||||
texture::TileConfig tileConfig;
|
||||
|
||||
GuestTexture(const DeviceState &state, u8 *pointer, texture::Dimensions dimensions, const texture::Format& format, texture::TileMode tileMode = texture::TileMode::Linear, texture::TileConfig tileConfig = {});
|
||||
GuestTexture(const DeviceState &state, u8 *pointer, texture::Dimensions dimensions, const texture::Format &format, texture::TileMode tileMode = texture::TileMode::Linear, texture::TileConfig tileConfig = {});
|
||||
|
||||
constexpr size_t Size() {
|
||||
return format.GetSize(dimensions);
|
||||
@ -206,18 +206,18 @@ namespace skyline::gpu {
|
||||
* @note There can only be one host texture for a corresponding guest texture
|
||||
* @note If any of the supplied parameters do not match up with the backing then it's undefined behavior
|
||||
*/
|
||||
std::shared_ptr<Texture> InitializeTexture(vk::Image backing, texture::Dimensions dimensions = {}, const texture::Format& format = {}, std::optional<vk::ImageTiling> tiling = std::nullopt, vk::ImageLayout layout = vk::ImageLayout::eUndefined, texture::Swizzle swizzle = {});
|
||||
std::shared_ptr<Texture> InitializeTexture(vk::Image backing, texture::Dimensions dimensions = {}, const texture::Format &format = {}, std::optional<vk::ImageTiling> tiling = std::nullopt, vk::ImageLayout layout = vk::ImageLayout::eUndefined, texture::Swizzle swizzle = {});
|
||||
|
||||
/**
|
||||
* @note As a RAII object is used here, the lifetime of the backing is handled by the host texture
|
||||
*/
|
||||
std::shared_ptr<Texture> InitializeTexture(vk::raii::Image &&backing, std::optional<vk::ImageTiling> tiling = std::nullopt, vk::ImageLayout layout = vk::ImageLayout::eUndefined, const texture::Format& format = {}, texture::Dimensions dimensions = {}, texture::Swizzle swizzle = {});
|
||||
std::shared_ptr<Texture> InitializeTexture(vk::raii::Image &&backing, std::optional<vk::ImageTiling> tiling = std::nullopt, vk::ImageLayout layout = vk::ImageLayout::eUndefined, const texture::Format &format = {}, texture::Dimensions dimensions = {}, texture::Swizzle swizzle = {});
|
||||
|
||||
/**
|
||||
* @brief Similar to InitializeTexture but creation of the backing and allocation of memory for the backing is automatically performed by the function
|
||||
* @param usage Usage flags that will applied aside from VK_IMAGE_USAGE_TRANSFER_SRC_BIT/VK_IMAGE_USAGE_TRANSFER_DST_BIT which are mandatory
|
||||
*/
|
||||
std::shared_ptr<Texture> CreateTexture(vk::ImageUsageFlags usage = {}, std::optional<vk::ImageTiling> tiling = std::nullopt, vk::ImageLayout initialLayout = vk::ImageLayout::eGeneral, const texture::Format& format = {}, texture::Dimensions dimensions = {}, texture::Swizzle swizzle = {});
|
||||
std::shared_ptr<Texture> CreateTexture(vk::ImageUsageFlags usage = {}, std::optional<vk::ImageTiling> tiling = std::nullopt, vk::ImageLayout initialLayout = vk::ImageLayout::eGeneral, const texture::Format &format = {}, texture::Dimensions dimensions = {}, texture::Swizzle swizzle = {});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -252,15 +252,15 @@ namespace skyline::gpu {
|
||||
vk::ImageTiling tiling;
|
||||
vk::ComponentMapping mapping;
|
||||
|
||||
Texture(GPU &gpu, BackingType &&backing, std::shared_ptr<GuestTexture> guest, texture::Dimensions dimensions, const texture::Format& format, vk::ImageLayout layout, vk::ImageTiling tiling, vk::ComponentMapping mapping);
|
||||
Texture(GPU &gpu, BackingType &&backing, std::shared_ptr<GuestTexture> guest, texture::Dimensions dimensions, const texture::Format &format, vk::ImageLayout layout, vk::ImageTiling tiling, vk::ComponentMapping mapping);
|
||||
|
||||
Texture(GPU &gpu, BackingType &&backing, texture::Dimensions dimensions, const texture::Format& format, vk::ImageLayout layout, vk::ImageTiling tiling, vk::ComponentMapping mapping = {});
|
||||
Texture(GPU &gpu, BackingType &&backing, texture::Dimensions dimensions, const texture::Format &format, vk::ImageLayout layout, vk::ImageTiling tiling, vk::ComponentMapping mapping = {});
|
||||
|
||||
/**
|
||||
* @brief Creates and allocates memory for the backing to creates a texture object wrapping it
|
||||
* @param usage Usage flags that will applied aside from VK_IMAGE_USAGE_TRANSFER_SRC_BIT/VK_IMAGE_USAGE_TRANSFER_DST_BIT which are mandatory
|
||||
*/
|
||||
Texture(GPU &gpu, texture::Dimensions dimensions, const texture::Format& format, vk::ImageLayout initialLayout = vk::ImageLayout::eGeneral, vk::ImageUsageFlags usage = {}, vk::ImageTiling tiling = vk::ImageTiling::eOptimal, vk::ComponentMapping mapping = {});
|
||||
Texture(GPU &gpu, texture::Dimensions dimensions, const texture::Format &format, vk::ImageLayout initialLayout = vk::ImageLayout::eGeneral, vk::ImageUsageFlags usage = {}, vk::ImageTiling tiling = vk::ImageTiling::eOptimal, vk::ComponentMapping mapping = {});
|
||||
|
||||
/**
|
||||
* @brief Acquires an exclusive lock on the texture for the calling thread
|
||||
|
Reference in New Issue
Block a user