فهرست منبع

Vulkan: Allow stagging buffer deferrals.

Fernando Sahmkow 3 سال پیش
والد
کامیت
2793304117
2فایلهای تغییر یافته به همراه56 افزوده شده و 21 حذف شده
  1. 36 15
      src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
  2. 20 6
      src/video_core/renderer_vulkan/vk_staging_buffer_pool.h

+ 36 - 15
src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp

@@ -1,5 +1,5 @@
-// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
 
 #include <algorithm>
 #include <utility>
@@ -94,7 +94,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
         .flags = 0,
         .size = STREAM_BUFFER_SIZE,
         .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
-                 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+                 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT ,
         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
         .queueFamilyIndexCount = 0,
         .pQueueFamilyIndices = nullptr,
@@ -142,11 +142,23 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
 
 StagingBufferPool::~StagingBufferPool() = default;
 
-StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage) {
-    if (usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) {
+StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage, bool deferred) {
+    if (!deferred && usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) {
         return GetStreamBuffer(size);
     }
-    return GetStagingBuffer(size, usage);
+    return GetStagingBuffer(size, usage, deferred);
+}
+
+void StagingBufferPool::FreeDeferred(StagingBufferRef& ref) {
+    auto& entries = GetCache(ref.usage)[ref.log2_level].entries;
+    const auto is_this_one = [&ref](const StagingBuffer& entry) {
+        return entry.index == ref.index;
+    };
+    auto it = std::find_if(entries.begin(), entries.end(), is_this_one);
+    ASSERT(it != entries.end());
+    ASSERT(it->deferred);
+    it->tick = scheduler.CurrentTick();
+    it->deferred = false;
 }
 
 void StagingBufferPool::TickFrame() {
@@ -196,19 +208,21 @@ bool StagingBufferPool::AreRegionsActive(size_t region_begin, size_t region_end)
                        [gpu_tick](u64 sync_tick) { return gpu_tick < sync_tick; });
 };
 
-StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage) {
-    if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage)) {
+StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage,
+                                                     bool deferred) {
+    if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage, deferred)) {
         return *ref;
     }
-    return CreateStagingBuffer(size, usage);
+    return CreateStagingBuffer(size, usage, deferred);
 }
 
 std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size,
-                                                                        MemoryUsage usage) {
+                                                                        MemoryUsage usage,
+                                                                        bool deferred) {
     StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)];
 
     const auto is_free = [this](const StagingBuffer& entry) {
-        return scheduler.IsFree(entry.tick);
+        return !entry.deferred && scheduler.IsFree(entry.tick);
     };
     auto& entries = cache_level.entries;
     const auto hint_it = entries.begin() + cache_level.iterate_index;
@@ -220,11 +234,14 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
         }
     }
     cache_level.iterate_index = std::distance(entries.begin(), it) + 1;
-    it->tick = scheduler.CurrentTick();
+    it->tick = deferred ? std::numeric_limits<u64>::max() : scheduler.CurrentTick();
+    ASSERT(!it->deferred);
+    it->deferred = deferred;
     return it->Ref();
 }
 
-StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage) {
+StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
+                                                        bool deferred) {
     const u32 log2 = Common::Log2Ceil64(size);
     vk::Buffer buffer = device.GetLogical().CreateBuffer({
         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
@@ -233,7 +250,7 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage
         .size = 1ULL << log2,
         .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
                  VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
-                 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
+                 VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT ,
         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
         .queueFamilyIndexCount = 0,
         .pQueueFamilyIndices = nullptr,
@@ -249,7 +266,11 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage
         .buffer = std::move(buffer),
         .commit = std::move(commit),
         .mapped_span = mapped_span,
-        .tick = scheduler.CurrentTick(),
+        .usage = usage,
+        .log2_level = log2,
+        .index = unique_ids++,
+        .tick = deferred ? std::numeric_limits<u64>::max() : scheduler.CurrentTick(),
+        .deferred = deferred,
     });
     return entry.Ref();
 }

+ 20 - 6
src/video_core/renderer_vulkan/vk_staging_buffer_pool.h

@@ -1,5 +1,6 @@
-// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
 
 #pragma once
 
@@ -20,6 +21,9 @@ struct StagingBufferRef {
     VkBuffer buffer;
     VkDeviceSize offset;
     std::span<u8> mapped_span;
+    MemoryUsage usage;
+    u32 log2_level;
+    u64 index;
 };
 
 class StagingBufferPool {
@@ -30,7 +34,8 @@ public:
                                Scheduler& scheduler);
     ~StagingBufferPool();
 
-    StagingBufferRef Request(size_t size, MemoryUsage usage);
+    StagingBufferRef Request(size_t size, MemoryUsage usage, bool deferred = false);
+    void FreeDeferred(StagingBufferRef& ref);
 
     void TickFrame();
 
@@ -44,13 +49,20 @@ private:
         vk::Buffer buffer;
         MemoryCommit commit;
         std::span<u8> mapped_span;
+        MemoryUsage usage;
+        u32 log2_level;
+        u64 index;
         u64 tick = 0;
+        bool deferred{};
 
         StagingBufferRef Ref() const noexcept {
             return {
                 .buffer = *buffer,
                 .offset = 0,
                 .mapped_span = mapped_span,
+                .usage = usage,
+                .log2_level = log2_level,
+                .index = index,
             };
         }
     };
@@ -68,11 +80,12 @@ private:
 
     bool AreRegionsActive(size_t region_begin, size_t region_end) const;
 
-    StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage);
+    StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage, bool deferred = false);
 
-    std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage);
+    std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage,
+                                                         bool deferred);
 
-    StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage);
+    StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage, bool deferred);
 
     StagingBuffersCache& GetCache(MemoryUsage usage);
 
@@ -99,6 +112,7 @@ private:
 
     size_t current_delete_level = 0;
     u64 buffer_index = 0;
+    u64 unique_ids{};
 };
 
 } // namespace Vulkan