mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 17:01:49 +01:00
Improve Vulkan Texture
Synchronization
The Vulkan Pipeline Barriers were unoptimal and incorrect to some degree prior as we purely synchronized images and not staging buffers. This has now been fixed and improved in general with more relevant synchronization.
This commit is contained in:
parent
bf71804089
commit
79ceb2cf23
@ -54,13 +54,13 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
void Texture::CopyFromStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer> &stagingBuffer) {
|
void Texture::CopyFromStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer> &stagingBuffer) {
|
||||||
auto image{GetBacking()};
|
auto image{GetBacking()};
|
||||||
if (layout != vk::ImageLayout::eTransferDstOptimal) {
|
if (layout == vk::ImageLayout::eUndefined)
|
||||||
commandBuffer.pipelineBarrier(layout != vk::ImageLayout::eUndefined ? vk::PipelineStageFlagBits::eTopOfPipe : vk::PipelineStageFlagBits::eBottomOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, vk::ImageMemoryBarrier{
|
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, vk::ImageMemoryBarrier{
|
||||||
.image = image,
|
.image = image,
|
||||||
.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
|
.srcAccessMask = vk::AccessFlagBits::eMemoryRead,
|
||||||
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
|
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||||
.oldLayout = layout,
|
.oldLayout = std::exchange(layout, vk::ImageLayout::eGeneral),
|
||||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
.newLayout = vk::ImageLayout::eGeneral,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.subresourceRange = {
|
.subresourceRange = {
|
||||||
@ -70,58 +70,33 @@ namespace skyline::gpu {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (layout == vk::ImageLayout::eUndefined)
|
commandBuffer.copyBufferToImage(stagingBuffer->vkBuffer, image, layout, vk::BufferImageCopy{
|
||||||
layout = vk::ImageLayout::eTransferDstOptimal;
|
|
||||||
}
|
|
||||||
|
|
||||||
commandBuffer.copyBufferToImage(stagingBuffer->vkBuffer, image, vk::ImageLayout::eTransferDstOptimal, vk::BufferImageCopy{
|
|
||||||
.imageExtent = dimensions,
|
.imageExtent = dimensions,
|
||||||
.imageSubresource = {
|
.imageSubresource = {
|
||||||
.aspectMask = format->vkAspect,
|
.aspectMask = format->vkAspect,
|
||||||
.layerCount = layerCount,
|
.layerCount = layerCount,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (layout != vk::ImageLayout::eTransferDstOptimal)
|
|
||||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, vk::ImageMemoryBarrier{
|
|
||||||
.image = image,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits::eMemoryRead,
|
|
||||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
||||||
.newLayout = layout,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.subresourceRange = {
|
|
||||||
.aspectMask = format->vkAspect,
|
|
||||||
.levelCount = mipLevels,
|
|
||||||
.layerCount = layerCount,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::CopyIntoStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer> &stagingBuffer) {
|
void Texture::CopyIntoStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer> &stagingBuffer) {
|
||||||
auto image{GetBacking()};
|
auto image{GetBacking()};
|
||||||
if (layout != vk::ImageLayout::eTransferSrcOptimal) {
|
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, vk::ImageMemoryBarrier{
|
||||||
commandBuffer.pipelineBarrier(layout != vk::ImageLayout::eUndefined ? vk::PipelineStageFlagBits::eTopOfPipe : vk::PipelineStageFlagBits::eBottomOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, vk::ImageMemoryBarrier{
|
.image = image,
|
||||||
.image = image,
|
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite,
|
||||||
.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
|
.dstAccessMask = vk::AccessFlagBits::eTransferRead,
|
||||||
.dstAccessMask = vk::AccessFlagBits::eTransferRead,
|
.oldLayout = layout,
|
||||||
.oldLayout = layout,
|
.newLayout = layout,
|
||||||
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.subresourceRange = {
|
||||||
.subresourceRange = {
|
.aspectMask = format->vkAspect,
|
||||||
.aspectMask = format->vkAspect,
|
.levelCount = mipLevels,
|
||||||
.levelCount = mipLevels,
|
.layerCount = layerCount,
|
||||||
.layerCount = layerCount,
|
},
|
||||||
},
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (layout == vk::ImageLayout::eUndefined)
|
commandBuffer.copyImageToBuffer(image, layout, stagingBuffer->vkBuffer, vk::BufferImageCopy{
|
||||||
layout = vk::ImageLayout::eTransferSrcOptimal;
|
|
||||||
}
|
|
||||||
|
|
||||||
commandBuffer.copyImageToBuffer(image, vk::ImageLayout::eTransferSrcOptimal, stagingBuffer->vkBuffer, vk::BufferImageCopy{
|
|
||||||
.imageExtent = dimensions,
|
.imageExtent = dimensions,
|
||||||
.imageSubresource = {
|
.imageSubresource = {
|
||||||
.aspectMask = format->vkAspect,
|
.aspectMask = format->vkAspect,
|
||||||
@ -129,21 +104,15 @@ namespace skyline::gpu {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (layout != vk::ImageLayout::eTransferSrcOptimal)
|
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eHost, {}, {}, vk::BufferMemoryBarrier{
|
||||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, vk::ImageMemoryBarrier{
|
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||||
.image = image,
|
.dstAccessMask = vk::AccessFlagBits::eHostRead,
|
||||||
.srcAccessMask = vk::AccessFlagBits::eTransferRead,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstAccessMask = vk::AccessFlagBits::eMemoryWrite,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.oldLayout = vk::ImageLayout::eTransferSrcOptimal,
|
.buffer = stagingBuffer->vkBuffer,
|
||||||
.newLayout = layout,
|
.offset = 0,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.size = stagingBuffer->size(),
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
}, {});
|
||||||
.subresourceRange = {
|
|
||||||
.aspectMask = format->vkAspect,
|
|
||||||
.levelCount = mipLevels,
|
|
||||||
.layerCount = layerCount,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::CopyToGuest(u8 *hostBuffer) {
|
void Texture::CopyToGuest(u8 *hostBuffer) {
|
||||||
@ -284,13 +253,13 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
TRACE_EVENT("gpu", "Texture::TransitionLayout");
|
TRACE_EVENT("gpu", "Texture::TransitionLayout");
|
||||||
|
|
||||||
if (layout != pLayout) {
|
if (layout != pLayout)
|
||||||
cycle = gpu.scheduler.Submit([&](vk::raii::CommandBuffer &commandBuffer) {
|
cycle = gpu.scheduler.Submit([&](vk::raii::CommandBuffer &commandBuffer) {
|
||||||
commandBuffer.pipelineBarrier(layout != vk::ImageLayout::eUndefined ? vk::PipelineStageFlagBits::eTopOfPipe : vk::PipelineStageFlagBits::eBottomOfPipe, vk::PipelineStageFlagBits::eBottomOfPipe, {}, {}, {}, vk::ImageMemoryBarrier{
|
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eBottomOfPipe, {}, {}, {}, vk::ImageMemoryBarrier{
|
||||||
.image = GetBacking(),
|
.image = GetBacking(),
|
||||||
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite,
|
.srcAccessMask = vk::AccessFlagBits::eNoneKHR,
|
||||||
.dstAccessMask = vk::AccessFlagBits::eMemoryRead,
|
.dstAccessMask = vk::AccessFlagBits::eNoneKHR,
|
||||||
.oldLayout = layout,
|
.oldLayout = std::exchange(layout, pLayout),
|
||||||
.newLayout = pLayout,
|
.newLayout = pLayout,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
@ -301,8 +270,6 @@ namespace skyline::gpu {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
layout = pLayout;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::SynchronizeHost() {
|
void Texture::SynchronizeHost() {
|
||||||
@ -339,6 +306,9 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
TRACE_EVENT("gpu", "Texture::SynchronizeGuest");
|
TRACE_EVENT("gpu", "Texture::SynchronizeGuest");
|
||||||
|
|
||||||
|
if (layout == vk::ImageLayout::eUndefined)
|
||||||
|
return; // We don't need to synchronize the image if it is in an undefined state on the host
|
||||||
|
|
||||||
WaitOnBacking();
|
WaitOnBacking();
|
||||||
WaitOnFence();
|
WaitOnFence();
|
||||||
|
|
||||||
@ -369,6 +339,9 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
TRACE_EVENT("gpu", "Texture::SynchronizeGuestWithBuffer");
|
TRACE_EVENT("gpu", "Texture::SynchronizeGuestWithBuffer");
|
||||||
|
|
||||||
|
if (layout == vk::ImageLayout::eUndefined)
|
||||||
|
return;
|
||||||
|
|
||||||
WaitOnBacking();
|
WaitOnBacking();
|
||||||
if (cycle.lock() != pCycle)
|
if (cycle.lock() != pCycle)
|
||||||
WaitOnFence();
|
WaitOnFence();
|
||||||
|
@ -347,6 +347,7 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Records commands for copying data from the texture's backing to a staging buffer into the supplied command buffer
|
* @brief Records commands for copying data from the texture's backing to a staging buffer into the supplied command buffer
|
||||||
|
* @note Any caller **must** ensure that the layout is not `eUndefined`
|
||||||
*/
|
*/
|
||||||
void CopyIntoStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer> &stagingBuffer);
|
void CopyIntoStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer> &stagingBuffer);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user