diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index fa68a14438..f3dfcab14d 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -142,6 +142,8 @@ public: bool HasNativeASTC() const noexcept; + void ReleaseSparseUnswizzleBuffer(Image& image) {} + void TickFrame() {} StateTracker& GetStateTracker() { diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 8c5634fb9e..39a92b9fb9 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -773,23 +773,7 @@ void BlockLinearUnswizzle3DPass::Unswizzle( } } - static constexpr u32 MAX_RUNS_PER_BATCH = 8; - const u32 min_run_len = (std::max)(4u, z_count / MAX_RUNS_PER_BATCH); - for (Run& r : runs) { - if (!r.has_data && r.len < min_run_len) { - r.has_data = true; - } - } - boost::container::small_vector merged; for (const Run& r : runs) { - if (!merged.empty() && merged.back().has_data == r.has_data) { - merged.back().len += r.len; - } else { - merged.push_back(r); - } - } - - for (const Run& r : merged) { u32 sub_offset = 0; while (sub_offset < r.len) { const u32 sub_len = (std::min)(r.len - sub_offset, MAX_BATCH_SLICES); @@ -797,52 +781,80 @@ void BlockLinearUnswizzle3DPass::Unswizzle( const u32 z_dst = z_image_start + r.start + sub_offset; if (!r.has_data) { - UnswizzleZeroChunk(image, z_dst, sub_len); + // Uncomment if junk data appears - FMX + //UnswizzleZeroChunk(image, z_dst, sub_len); sub_offset += sub_len; continue; } - u32 ox0 = 0, oy0 = 0, ox1 = blocks_x, oy1 = blocks_y; - if (!slice_bounds.empty()) { - bool any = false; - u32 ux0 = blocks_x, uy0 = blocks_y, ux1 = 0, uy1 = 0; - for (u32 z = z_src; z < z_src + sub_len; ++z) { - if (z >= static_cast(slice_bounds.size())) { any = false; break; } - const auto& b = slice_bounds[z]; - if (b.x1 <= b.x0 || b.y1 <= b.y0) continue; - ux0 = (std::min)(ux0, b.x0); - uy0 = (std::min)(uy0, b.y0); - ux1 = (std::max)(ux1, b.x1); - uy1 = (std::max)(uy1, b.y1); - any = true; + u32 win_offset = 0; + while (win_offset < sub_len) { + const u32 win_len = (std::min)(sub_len - win_offset, 1u); + const u32 wz_src = z_src + win_offset; + const u32 wz_dst = z_dst + win_offset; + + u32 ox0 = 0, oy0 = 0, ox1 = blocks_x, oy1 = blocks_y; + bool window_is_empty = false; + + if (!slice_bounds.empty()) { + bool has_valid_bounds = false; + bool out_of_bounds = false; + u32 ux0 = blocks_x, uy0 = blocks_y, ux1 = 0, uy1 = 0; + + for (u32 z = wz_src; z < wz_src + win_len; ++z) { + if (z >= static_cast(slice_bounds.size())) { + out_of_bounds = true; + break; + } + const auto& b = slice_bounds[z]; + + if (b.x1 <= b.x0 || b.y1 <= b.y0) continue; + + ux0 = (std::min)(ux0, b.x0); + uy0 = (std::min)(uy0, b.y0); + ux1 = (std::max)(ux1, b.x1); + uy1 = (std::max)(uy1, b.y1); + has_valid_bounds = true; + } + + if (out_of_bounds) { + ox0 = 0; oy0 = 0; ox1 = blocks_x; oy1 = blocks_y; + } else if (has_valid_bounds) { + ox0 = ux0; oy0 = uy0; ox1 = ux1; oy1 = uy1; + } else { + window_is_empty = true; + } + } + + if (window_is_empty) { + win_offset += win_len; + continue; } - if (any) { ox0 = ux0; oy0 = uy0; ox1 = ux1; oy1 = uy1; } - } - // Uncomment if garbage data starts appearing - //UnswizzleZeroChunk(image, z_dst, sub_len); - - scheduler.Record([dst_image = image.Handle(), aspect = image.AspectMask()](vk::CommandBuffer cmdbuf) { - if (dst_image == VK_NULL_HANDLE) return; - const VkImageMemoryBarrier barrier{ - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = dst_image, - .subresourceRange = {aspect, 0, 1, 0, 1}, - }; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, barrier); - }); - - UnswizzleChunk(image, swizzled, sw, params, - ox0, oy0, ox1 - ox0, oy1 - oy0, - z_src, z_dst, sub_len); + scheduler.Record([dst_image = image.Handle(), aspect = image.AspectMask()](vk::CommandBuffer cmdbuf) { + if (dst_image == VK_NULL_HANDLE) return; + const VkImageMemoryBarrier barrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange = {aspect, 0, 1, 0, 1}, + }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, barrier); + }); + + UnswizzleChunk(image, swizzled, sw, params, + ox0, oy0, ox1 - ox0, oy1 - oy0, + wz_src, wz_dst, win_len); + + win_offset += win_len; + } sub_offset += sub_len; } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 0fe43466e3..3397282e0a 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1769,6 +1769,16 @@ std::optional TextureCacheRuntime::GetSamplerHeapBudget() const { } void TextureCacheRuntime::TickFrame() { + sentenced_unswizzle_buffers.Tick(); +} + +void TextureCacheRuntime::ReleaseSparseUnswizzleBuffer(Image& image) { + if (image.has_compute_unswizzle_buffer) { + sentenced_unswizzle_buffers.Push(std::move(image.compute_unswizzle_buffer)); + image.has_compute_unswizzle_buffer = false; + image.compute_unswizzle_buffer_size = 0; + image.compute_unswizzle_buffer_is_zero = false; + } std::erase_if(pending_msaa_images, [this](const auto& pending) { return scheduler.IsFree(pending.first); }); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 0f1422c350..b6ca70da58 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -17,6 +17,7 @@ #include "video_core/texture_cache/image_view_base.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +#include "video_core/delayed_destruction_ring.h" namespace Settings { struct ResolutionScalingInfo; @@ -58,6 +59,8 @@ public: void FreeDeferredStagingBuffer(StagingBufferRef& ref); + void ReleaseSparseUnswizzleBuffer(Image& image); + void TickFrame(); u64 GetDeviceLocalMemory() const; @@ -157,6 +160,8 @@ public: static constexpr size_t indexing_slots = 8 * sizeof(size_t); std::array buffers{}; + + VideoCommon::DelayedDestructionRing sentenced_unswizzle_buffers; std::vector> pending_msaa_images; ankerl::unordered_dense::map resolve_shadows; }; @@ -327,6 +332,7 @@ public: u64 allocation_tick; friend class BlockLinearUnswizzle3DPass; + friend class TextureCacheRuntime; private: bool BlitScaleHelper(bool scale_up); diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 8b6b86e35f..d7dd9eb17e 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1634,6 +1634,7 @@ void TextureCache

::TickAsyncUnswizzle() { runtime.FreeDeferredStagingBuffer(task.staging_buffer); image.flags &= ~ImageFlagBits::IsDecoding; + runtime.ReleaseSparseUnswizzleBuffer(image); unswizzle_queue.pop_front(); } }