summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-12-30 12:25:59 -0400
committerGravatar GitHub2019-12-30 12:25:59 -0400
commit287d5921cf3f159642361b7dcdf1b02355e3cc80 (patch)
tree6ab5ad70b616d818464de68ac2498b3d770ef93c /src
parentMerge pull request #3250 from ReinUsesLisp/empty-fragment (diff)
parentvk_staging_buffer_pool: Initialize last epoch to zero (diff)
downloadyuzu-287d5921cf3f159642361b7dcdf1b02355e3cc80.tar.gz
yuzu-287d5921cf3f159642361b7dcdf1b02355e3cc80.tar.xz
yuzu-287d5921cf3f159642361b7dcdf1b02355e3cc80.zip
Merge pull request #3249 from ReinUsesLisp/vk-staging-buffer-pool
vk_staging_buffer_pool: Add a staging pool for temporary operations
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp127
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.h83
3 files changed, 212 insertions, 0 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index e615b238e..fcedad3fa 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -169,6 +169,8 @@ if (ENABLE_VULKAN)
169 renderer_vulkan/vk_scheduler.h 169 renderer_vulkan/vk_scheduler.h
170 renderer_vulkan/vk_shader_decompiler.cpp 170 renderer_vulkan/vk_shader_decompiler.cpp
171 renderer_vulkan/vk_shader_decompiler.h 171 renderer_vulkan/vk_shader_decompiler.h
172 renderer_vulkan/vk_staging_buffer_pool.cpp
173 renderer_vulkan/vk_staging_buffer_pool.h
172 renderer_vulkan/vk_stream_buffer.cpp 174 renderer_vulkan/vk_stream_buffer.cpp
173 renderer_vulkan/vk_stream_buffer.h 175 renderer_vulkan/vk_stream_buffer.h
174 renderer_vulkan/vk_swapchain.cpp 176 renderer_vulkan/vk_swapchain.cpp
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
new file mode 100644
index 000000000..171d78afc
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -0,0 +1,127 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <unordered_map>
7#include <utility>
8#include <vector>
9
10#include "common/bit_util.h"
11#include "common/common_types.h"
12#include "video_core/renderer_vulkan/vk_device.h"
13#include "video_core/renderer_vulkan/vk_resource_manager.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h"
15#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
16
17namespace Vulkan {
18
19VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer, VKFence& fence,
20 u64 last_epoch)
21 : buffer{std::move(buffer)}, watch{fence}, last_epoch{last_epoch} {}
22
23VKStagingBufferPool::StagingBuffer::StagingBuffer(StagingBuffer&& rhs) noexcept {
24 buffer = std::move(rhs.buffer);
25 watch = std::move(rhs.watch);
26 last_epoch = rhs.last_epoch;
27}
28
29VKStagingBufferPool::StagingBuffer::~StagingBuffer() = default;
30
31VKStagingBufferPool::StagingBuffer& VKStagingBufferPool::StagingBuffer::operator=(
32 StagingBuffer&& rhs) noexcept {
33 buffer = std::move(rhs.buffer);
34 watch = std::move(rhs.watch);
35 last_epoch = rhs.last_epoch;
36 return *this;
37}
38
39VKStagingBufferPool::VKStagingBufferPool(const VKDevice& device, VKMemoryManager& memory_manager,
40 VKScheduler& scheduler)
41 : device{device}, memory_manager{memory_manager}, scheduler{scheduler},
42 is_device_integrated{device.IsIntegrated()} {}
43
44VKStagingBufferPool::~VKStagingBufferPool() = default;
45
46VKBuffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visible) {
47 if (const auto buffer = TryGetReservedBuffer(size, host_visible)) {
48 return *buffer;
49 }
50 return CreateStagingBuffer(size, host_visible);
51}
52
53void VKStagingBufferPool::TickFrame() {
54 ++epoch;
55 current_delete_level = (current_delete_level + 1) % NumLevels;
56
57 ReleaseCache(true);
58 if (!is_device_integrated) {
59 ReleaseCache(false);
60 }
61}
62
63VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) {
64 for (auto& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) {
65 if (entry.watch.TryWatch(scheduler.GetFence())) {
66 entry.last_epoch = epoch;
67 return &*entry.buffer;
68 }
69 }
70 return nullptr;
71}
72
73VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) {
74 const auto usage =
75 vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst |
76 vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer;
77 const u32 log2 = Common::Log2Ceil64(size);
78 const vk::BufferCreateInfo buffer_ci({}, 1ULL << log2, usage, vk::SharingMode::eExclusive, 0,
79 nullptr);
80 const auto dev = device.GetLogical();
81 auto buffer = std::make_unique<VKBuffer>();
82 buffer->handle = dev.createBufferUnique(buffer_ci, nullptr, device.GetDispatchLoader());
83 buffer->commit = memory_manager.Commit(*buffer->handle, host_visible);
84
85 auto& entries = GetCache(host_visible)[log2].entries;
86 return *entries.emplace_back(std::move(buffer), scheduler.GetFence(), epoch).buffer;
87}
88
89VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) {
90 return is_device_integrated || host_visible ? host_staging_buffers : device_staging_buffers;
91}
92
93void VKStagingBufferPool::ReleaseCache(bool host_visible) {
94 auto& cache = GetCache(host_visible);
95 const u64 size = ReleaseLevel(cache, current_delete_level);
96 if (size == 0) {
97 return;
98 }
99}
100
101u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t log2) {
102 static constexpr u64 epochs_to_destroy = 180;
103 static constexpr std::size_t deletions_per_tick = 16;
104
105 auto& staging = cache[log2];
106 auto& entries = staging.entries;
107 const std::size_t old_size = entries.size();
108
109 const auto is_deleteable = [this](const auto& entry) {
110 return entry.last_epoch + epochs_to_destroy < epoch && !entry.watch.IsUsed();
111 };
112 const std::size_t begin_offset = staging.delete_index;
113 const std::size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size);
114 const auto begin = std::begin(entries) + begin_offset;
115 const auto end = std::begin(entries) + end_offset;
116 entries.erase(std::remove_if(begin, end, is_deleteable), end);
117
118 const std::size_t new_size = entries.size();
119 staging.delete_index += deletions_per_tick;
120 if (staging.delete_index >= new_size) {
121 staging.delete_index = 0;
122 }
123
124 return (1ULL << log2) * (old_size - new_size);
125}
126
127} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
new file mode 100644
index 000000000..02310375f
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
@@ -0,0 +1,83 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <climits>
8#include <unordered_map>
9#include <utility>
10#include <vector>
11
12#include "common/common_types.h"
13
14#include "video_core/renderer_vulkan/declarations.h"
15#include "video_core/renderer_vulkan/vk_memory_manager.h"
16
17namespace Vulkan {
18
19class VKDevice;
20class VKFenceWatch;
21class VKScheduler;
22
23struct VKBuffer final {
24 UniqueBuffer handle;
25 VKMemoryCommit commit;
26};
27
28class VKStagingBufferPool final {
29public:
30 explicit VKStagingBufferPool(const VKDevice& device, VKMemoryManager& memory_manager,
31 VKScheduler& scheduler);
32 ~VKStagingBufferPool();
33
34 VKBuffer& GetUnusedBuffer(std::size_t size, bool host_visible);
35
36 void TickFrame();
37
38private:
39 struct StagingBuffer final {
40 explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer, VKFence& fence, u64 last_epoch);
41 StagingBuffer(StagingBuffer&& rhs) noexcept;
42 StagingBuffer(const StagingBuffer&) = delete;
43 ~StagingBuffer();
44
45 StagingBuffer& operator=(StagingBuffer&& rhs) noexcept;
46
47 std::unique_ptr<VKBuffer> buffer;
48 VKFenceWatch watch;
49 u64 last_epoch = 0;
50 };
51
52 struct StagingBuffers final {
53 std::vector<StagingBuffer> entries;
54 std::size_t delete_index = 0;
55 };
56
57 static constexpr std::size_t NumLevels = sizeof(std::size_t) * CHAR_BIT;
58 using StagingBuffersCache = std::array<StagingBuffers, NumLevels>;
59
60 VKBuffer* TryGetReservedBuffer(std::size_t size, bool host_visible);
61
62 VKBuffer& CreateStagingBuffer(std::size_t size, bool host_visible);
63
64 StagingBuffersCache& GetCache(bool host_visible);
65
66 void ReleaseCache(bool host_visible);
67
68 u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2);
69
70 const VKDevice& device;
71 VKMemoryManager& memory_manager;
72 VKScheduler& scheduler;
73 const bool is_device_integrated;
74
75 StagingBuffersCache host_staging_buffers;
76 StagingBuffersCache device_staging_buffers;
77
78 u64 epoch = 0;
79
80 std::size_t current_delete_level = 0;
81};
82
83} // namespace Vulkan