diff --git a/src/video_core/renderer_vulkan/vk_blit_helper.cpp b/src/video_core/renderer_vulkan/vk_blit_helper.cpp index 0d530ac95..e4fc489ef 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_helper.cpp @@ -523,6 +523,11 @@ bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion, {}, {}, post_barriers); }); + + if (multisample) { + // Resolve the destination image if needed + ResolveTexture(dest); + } return true; } @@ -601,6 +606,99 @@ bool BlitHelper::DepthToBuffer(Surface& source, vk::Buffer buffer, return true; } +void BlitHelper::ResolveTexture(Surface& surface) { + + scheduler.Record([width = surface.GetScaledWidth(), height = surface.GetScaledHeight(), + aspect = surface.Aspect(), access_flags = surface.AccessFlags(), + pipeline_state_flags = surface.PipelineStageFlags(), + msaa_image = surface.Image(Type::MultiSampled), + dest_image = surface.Image()](vk::CommandBuffer cmdbuf) { + const vk::ImageResolve resolve_area = { + .srcSubresource{ + .aspectMask = aspect, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .srcOffset = {}, + .dstSubresource{ + .aspectMask = aspect, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .dstOffset = {}, + .extent{ + .width = width, + .height = height, + .depth = 1, + }, + }; + + const vk::ImageSubresourceRange subresource_range = vk::ImageSubresourceRange{ + .aspectMask = aspect, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }; + + const std::array read_barriers = { + vk::ImageMemoryBarrier{ + .srcAccessMask = access_flags, + .dstAccessMask = vk::AccessFlagBits::eTransferRead, + .oldLayout = vk::ImageLayout::eGeneral, + .newLayout = vk::ImageLayout::eTransferSrcOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = msaa_image, + .subresourceRange = subresource_range, + }, + vk::ImageMemoryBarrier{ + .srcAccessMask = access_flags, + .dstAccessMask = vk::AccessFlagBits::eTransferWrite, + .oldLayout = vk::ImageLayout::eGeneral, + .newLayout = vk::ImageLayout::eTransferDstOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dest_image, + .subresourceRange = subresource_range, + }, + }; + const std::array write_barriers = { + vk::ImageMemoryBarrier{ + .srcAccessMask = vk::AccessFlagBits::eTransferRead, + .dstAccessMask = access_flags, + .oldLayout = vk::ImageLayout::eTransferSrcOptimal, + .newLayout = vk::ImageLayout::eGeneral, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = msaa_image, + .subresourceRange = subresource_range, + }, + vk::ImageMemoryBarrier{ + .srcAccessMask = vk::AccessFlagBits::eTransferWrite, + .dstAccessMask = access_flags, + .oldLayout = vk::ImageLayout::eTransferDstOptimal, + .newLayout = vk::ImageLayout::eGeneral, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dest_image, + .subresourceRange = subresource_range, + }, + }; + + cmdbuf.pipelineBarrier(pipeline_state_flags, vk::PipelineStageFlagBits::eTransfer, + vk::DependencyFlagBits::eByRegion, {}, {}, read_barriers); + + cmdbuf.resolveImage(msaa_image, vk::ImageLayout::eTransferSrcOptimal, dest_image, + vk::ImageLayout::eTransferDstOptimal, resolve_area); + + cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, pipeline_state_flags, + vk::DependencyFlagBits::eByRegion, {}, {}, write_barriers); + }); +} + vk::Pipeline BlitHelper::MakeComputePipeline(vk::ShaderModule shader, vk::PipelineLayout layout) { const vk::ComputePipelineCreateInfo compute_info = { .stage = MakeStages(shader), diff --git a/src/video_core/renderer_vulkan/vk_blit_helper.h b/src/video_core/renderer_vulkan/vk_blit_helper.h index 16e0090b0..e9ea63cac 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.h +++ b/src/video_core/renderer_vulkan/vk_blit_helper.h @@ -39,6 +39,8 @@ public: bool DepthToBuffer(Surface& source, vk::Buffer buffer, const VideoCore::BufferTextureCopy& copy); + void ResolveTexture(Surface& surface); + private: vk::Pipeline MakeComputePipeline(vk::ShaderModule shader, vk::PipelineLayout layout); vk::Pipeline MakeDepthStencilBlitPipeline(); diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp index 1bbbe9969..9420bcfb7 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.cpp @@ -495,93 +495,6 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface, }); } -void TextureRuntime::ResolveTexture(Surface& surface) { - - scheduler.Record([width = surface.GetScaledWidth(), height = surface.GetScaledHeight(), - aspect = surface.Aspect(), access_flags = surface.AccessFlags(), - pipeline_state_flags = surface.PipelineStageFlags(), - msaa_image = surface.Image(Type::MultiSampled), - dest_image = surface.Image()](vk::CommandBuffer cmdbuf) { - const vk::ImageResolve resolve_area = { - .srcSubresource{ - .aspectMask = aspect, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .srcOffset = {}, - .dstSubresource{ - .aspectMask = aspect, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .dstOffset = {}, - .extent{ - .width = width, - .height = height, - .depth = 1, - }, - }; - - const vk::ImageSubresourceRange subresource_range = MakeSubresourceRange(aspect, 0); - - const std::array read_barriers = { - vk::ImageMemoryBarrier{ - .srcAccessMask = access_flags, - .dstAccessMask = vk::AccessFlagBits::eTransferRead, - .oldLayout = vk::ImageLayout::eGeneral, - .newLayout = vk::ImageLayout::eTransferSrcOptimal, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = msaa_image, - .subresourceRange = subresource_range, - }, - vk::ImageMemoryBarrier{ - .srcAccessMask = access_flags, - .dstAccessMask = vk::AccessFlagBits::eTransferWrite, - .oldLayout = vk::ImageLayout::eGeneral, - .newLayout = vk::ImageLayout::eTransferDstOptimal, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = dest_image, - .subresourceRange = subresource_range, - }, - }; - const std::array write_barriers = { - vk::ImageMemoryBarrier{ - .srcAccessMask = vk::AccessFlagBits::eTransferRead, - .dstAccessMask = access_flags, - .oldLayout = vk::ImageLayout::eTransferSrcOptimal, - .newLayout = vk::ImageLayout::eGeneral, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = msaa_image, - .subresourceRange = subresource_range, - }, - vk::ImageMemoryBarrier{ - .srcAccessMask = vk::AccessFlagBits::eTransferWrite, - .dstAccessMask = access_flags, - .oldLayout = vk::ImageLayout::eTransferDstOptimal, - .newLayout = vk::ImageLayout::eGeneral, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = dest_image, - .subresourceRange = subresource_range, - }, - }; - - cmdbuf.pipelineBarrier(pipeline_state_flags, vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eByRegion, {}, {}, read_barriers); - - cmdbuf.resolveImage(msaa_image, vk::ImageLayout::eTransferSrcOptimal, dest_image, - vk::ImageLayout::eTransferDstOptimal, resolve_area); - - cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, pipeline_state_flags, - vk::DependencyFlagBits::eByRegion, {}, {}, write_barriers); - }); -} - bool TextureRuntime::CopyTextures(Surface& source, Surface& dest, std::span copies) { renderpass_cache.EndRendering(); @@ -697,10 +610,10 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest, // Must resolve images first // Todo(wunk): Add a "dirty" flag for msaa resolves to avoid redundant image resolves if (source.sample_count > 1) { - ResolveTexture(source); + blit_helper.ResolveTexture(source); } if (dest.sample_count > 1) { - ResolveTexture(dest); + blit_helper.ResolveTexture(dest); } const RecordParams params = { diff --git a/src/video_core/renderer_vulkan/vk_texture_runtime.h b/src/video_core/renderer_vulkan/vk_texture_runtime.h index 7bffdd373..18bd7cafa 100644 --- a/src/video_core/renderer_vulkan/vk_texture_runtime.h +++ b/src/video_core/renderer_vulkan/vk_texture_runtime.h @@ -163,9 +163,6 @@ private: /// Clears a partial texture rect using a clear rectangle void ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear); - /// Resolves the multi-sampled texture of a surface, if available, into the current texture - void ResolveTexture(Surface& surface); - private: const Instance& instance; Scheduler& scheduler;