summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp116
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h87
3 files changed, 205 insertions, 0 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 60529323e..3e9d2b3be 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -104,6 +104,8 @@ add_library(video_core STATIC
104if (ENABLE_VULKAN) 104if (ENABLE_VULKAN)
105 target_sources(video_core PRIVATE 105 target_sources(video_core PRIVATE
106 renderer_vulkan/declarations.h 106 renderer_vulkan/declarations.h
107 renderer_vulkan/vk_buffer_cache.cpp
108 renderer_vulkan/vk_buffer_cache.h
107 renderer_vulkan/vk_device.cpp 109 renderer_vulkan/vk_device.cpp
108 renderer_vulkan/vk_device.h 110 renderer_vulkan/vk_device.h
109 renderer_vulkan/vk_memory_manager.cpp 111 renderer_vulkan/vk_memory_manager.cpp
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
new file mode 100644
index 000000000..18b7b94a1
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -0,0 +1,116 @@
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 <cstring>
6#include <memory>
7#include <optional>
8#include <tuple>
9
10#include "common/alignment.h"
11#include "core/core.h"
12#include "core/memory.h"
13#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_buffer_cache.h"
15#include "video_core/renderer_vulkan/vk_scheduler.h"
16#include "video_core/renderer_vulkan/vk_stream_buffer.h"
17
18namespace Vulkan {
19
20VKBufferCache::VKBufferCache(Tegra::MemoryManager& tegra_memory_manager,
21 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
22 VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size)
23 : RasterizerCache{rasterizer}, tegra_memory_manager{tegra_memory_manager} {
24 const auto usage = vk::BufferUsageFlagBits::eVertexBuffer |
25 vk::BufferUsageFlagBits::eIndexBuffer |
26 vk::BufferUsageFlagBits::eUniformBuffer;
27 const auto access = vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndexRead |
28 vk::AccessFlagBits::eUniformRead;
29 stream_buffer =
30 std::make_unique<VKStreamBuffer>(device, memory_manager, scheduler, size, usage, access,
31 vk::PipelineStageFlagBits::eAllCommands);
32 buffer_handle = stream_buffer->GetBuffer();
33}
34
35VKBufferCache::~VKBufferCache() = default;
36
37u64 VKBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, u64 alignment,
38 bool cache) {
39 const auto cpu_addr{tegra_memory_manager.GpuToCpuAddress(gpu_addr)};
40 ASSERT(cpu_addr);
41
42 // Cache management is a big overhead, so only cache entries with a given size.
43 // TODO: Figure out which size is the best for given games.
44 cache &= size >= 2048;
45
46 if (cache) {
47 if (auto entry = TryGet(*cpu_addr); entry) {
48 if (entry->size >= size && entry->alignment == alignment) {
49 return entry->offset;
50 }
51 Unregister(entry);
52 }
53 }
54
55 AlignBuffer(alignment);
56 const u64 uploaded_offset = buffer_offset;
57
58 Memory::ReadBlock(*cpu_addr, buffer_ptr, size);
59
60 buffer_ptr += size;
61 buffer_offset += size;
62
63 if (cache) {
64 auto entry = std::make_shared<CachedBufferEntry>();
65 entry->offset = uploaded_offset;
66 entry->size = size;
67 entry->alignment = alignment;
68 entry->addr = *cpu_addr;
69 Register(entry);
70 }
71
72 return uploaded_offset;
73}
74
75u64 VKBufferCache::UploadHostMemory(const u8* raw_pointer, std::size_t size, u64 alignment) {
76 AlignBuffer(alignment);
77 std::memcpy(buffer_ptr, raw_pointer, size);
78 const u64 uploaded_offset = buffer_offset;
79
80 buffer_ptr += size;
81 buffer_offset += size;
82 return uploaded_offset;
83}
84
85std::tuple<u8*, u64> VKBufferCache::ReserveMemory(std::size_t size, u64 alignment) {
86 AlignBuffer(alignment);
87 u8* const uploaded_ptr = buffer_ptr;
88 const u64 uploaded_offset = buffer_offset;
89
90 buffer_ptr += size;
91 buffer_offset += size;
92 return {uploaded_ptr, uploaded_offset};
93}
94
95void VKBufferCache::Reserve(std::size_t max_size) {
96 bool invalidate;
97 std::tie(buffer_ptr, buffer_offset_base, invalidate) = stream_buffer->Reserve(max_size);
98 buffer_offset = buffer_offset_base;
99
100 if (invalidate) {
101 InvalidateAll();
102 }
103}
104
105VKExecutionContext VKBufferCache::Send(VKExecutionContext exctx) {
106 return stream_buffer->Send(exctx, buffer_offset - buffer_offset_base);
107}
108
109void VKBufferCache::AlignBuffer(std::size_t alignment) {
110 // Align the offset, not the mapped pointer
111 const u64 offset_aligned = Common::AlignUp(buffer_offset, alignment);
112 buffer_ptr += offset_aligned - buffer_offset;
113 buffer_offset = offset_aligned;
114}
115
116} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
new file mode 100644
index 000000000..6cbe21202
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -0,0 +1,87 @@
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 <memory>
8#include <tuple>
9
10#include "common/common_types.h"
11#include "video_core/gpu.h"
12#include "video_core/rasterizer_cache.h"
13#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h"
15
16namespace Tegra {
17class MemoryManager;
18}
19
20namespace Vulkan {
21
22class VKDevice;
23class VKFence;
24class VKMemoryManager;
25class VKStreamBuffer;
26
27struct CachedBufferEntry final : public RasterizerCacheObject {
28 VAddr GetAddr() const override {
29 return addr;
30 }
31
32 std::size_t GetSizeInBytes() const override {
33 return size;
34 }
35
36 // We do not have to flush this cache as things in it are never modified by us.
37 void Flush() override {}
38
39 VAddr addr;
40 std::size_t size;
41 u64 offset;
42 std::size_t alignment;
43};
44
45class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
46public:
47 explicit VKBufferCache(Tegra::MemoryManager& tegra_memory_manager, VideoCore::RasterizerInterface& rasterizer,
48 const VKDevice& device, VKMemoryManager& memory_manager,
49 VKScheduler& scheduler, u64 size);
50 ~VKBufferCache();
51
52 /// Uploads data from a guest GPU address. Returns host's buffer offset where it's been
53 /// allocated.
54 u64 UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, u64 alignment = 4,
55 bool cache = true);
56
57 /// Uploads from a host memory. Returns host's buffer offset where it's been allocated.
58 u64 UploadHostMemory(const u8* raw_pointer, std::size_t size, u64 alignment = 4);
59
60 /// Reserves memory to be used by host's CPU. Returns mapped address and offset.
61 std::tuple<u8*, u64> ReserveMemory(std::size_t size, u64 alignment = 4);
62
63 /// Reserves a region of memory to be used in subsequent upload/reserve operations.
64 void Reserve(std::size_t max_size);
65
66 /// Ensures that the set data is sent to the device.
67 [[nodiscard]] VKExecutionContext Send(VKExecutionContext exctx);
68
69 /// Returns the buffer cache handle.
70 vk::Buffer GetBuffer() const {
71 return buffer_handle;
72 }
73
74private:
75 void AlignBuffer(std::size_t alignment);
76
77 Tegra::MemoryManager& tegra_memory_manager;
78
79 std::unique_ptr<VKStreamBuffer> stream_buffer;
80 vk::Buffer buffer_handle;
81
82 u8* buffer_ptr = nullptr;
83 u64 buffer_offset = 0;
84 u64 buffer_offset_base = 0;
85};
86
87} // namespace Vulkan