summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-05-27 20:50:11 -0300
committerGravatar ReinUsesLisp2019-07-06 00:37:55 -0300
commit8155b12d3d8963ec4d8727614ffb522a33389cbf (patch)
tree99ca355ef1c1bdecc990ddd76ac460e500133717 /src
parentgl_buffer_cache: Store in CachedBufferEntry the used buffer handle (diff)
downloadyuzu-8155b12d3d8963ec4d8727614ffb522a33389cbf.tar.gz
yuzu-8155b12d3d8963ec4d8727614ffb522a33389cbf.tar.xz
yuzu-8155b12d3d8963ec4d8727614ffb522a33389cbf.zip
gl_buffer_cache: Rework to support internalized buffers
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp167
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h70
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
3 files changed, 174 insertions, 65 deletions
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index b4277ef73..1219ca6ea 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -7,90 +7,165 @@
7#include <utility> 7#include <utility>
8 8
9#include "common/alignment.h" 9#include "common/alignment.h"
10#include "common/assert.h"
10#include "core/core.h" 11#include "core/core.h"
11#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
12#include "video_core/renderer_opengl/gl_buffer_cache.h" 13#include "video_core/renderer_opengl/gl_buffer_cache.h"
13#include "video_core/renderer_opengl/gl_rasterizer.h" 14#include "video_core/renderer_opengl/gl_rasterizer.h"
15#include "video_core/renderer_opengl/gl_resource_manager.h"
14 16
15namespace OpenGL { 17namespace OpenGL {
16 18
17CachedBufferEntry::CachedBufferEntry(VAddr cpu_addr, u8* host_ptr, std::size_t size, 19namespace {
18 std::size_t alignment, GLuint buffer, GLintptr offset) 20
19 : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr}, size{size}, alignment{alignment}, 21constexpr GLuint EmptyBuffer = 0;
20 buffer{buffer}, offset{offset} {} 22constexpr GLintptr CachedBufferOffset = 0;
23
24OGLBuffer CreateBuffer(std::size_t size, GLenum usage) {
25 OGLBuffer buffer;
26 buffer.Create();
27 glNamedBufferData(buffer.handle, size, nullptr, usage);
28 return buffer;
29}
30
31} // Anonymous namespace
32
33CachedBufferEntry::CachedBufferEntry(VAddr cpu_addr, u8* host_ptr)
34 : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr} {}
21 35
22OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size) 36OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size)
23 : RasterizerCache{rasterizer}, stream_buffer(size, true) {} 37 : RasterizerCache{rasterizer}, stream_buffer(size, true) {}
24 38
25std::pair<GLuint, GLintptr> OGLBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size, 39OGLBufferCache::~OGLBufferCache() = default;
26 std::size_t alignment, bool cache) { 40
41void OGLBufferCache::Unregister(const std::shared_ptr<CachedBufferEntry>& entry) {
27 std::lock_guard lock{mutex}; 42 std::lock_guard lock{mutex};
28 43
29 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager(); 44 if (entry->IsInternalized()) {
45 internalized_entries.erase(entry->GetCacheAddr());
46 }
47 ReserveBuffer(entry);
48 RasterizerCache<std::shared_ptr<CachedBufferEntry>>::Unregister(entry);
49}
50
51OGLBufferCache::BufferInfo OGLBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size,
52 std::size_t alignment, bool internalize) {
53 std::lock_guard lock{mutex};
30 54
31 const auto& host_ptr{memory_manager.GetPointer(gpu_addr)}; 55 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
56 const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
57 const auto cache_addr{ToCacheAddr(host_ptr)};
32 if (!host_ptr) { 58 if (!host_ptr) {
33 // Return a dummy buffer when host_ptr is invalid. 59 return {EmptyBuffer, 0};
34 return {0, 0};
35 } 60 }
36 61
37 // Cache management is a big overhead, so only cache entries with a given size. 62 // Cache management is a big overhead, so only cache entries with a given size.
38 // TODO: Figure out which size is the best for given games. 63 // TODO: Figure out which size is the best for given games.
39 cache &= size >= 2048; 64 if (!internalize && size < 0x800 &&
40 65 internalized_entries.find(cache_addr) == internalized_entries.end()) {
41 if (cache) { 66 return StreamBufferUpload(host_ptr, size, alignment);
42 if (auto entry = TryGet(host_ptr); entry) {
43 if (entry->GetSize() >= size && entry->GetAlignment() == alignment) {
44 return {entry->GetBuffer(), entry->GetOffset()};
45 }
46 Unregister(entry);
47 }
48 } 67 }
49 68
50 AlignBuffer(alignment); 69 auto entry = TryGet(host_ptr);
51 const GLintptr uploaded_offset = buffer_offset; 70 if (!entry) {
52 71 return FixedBufferUpload(gpu_addr, host_ptr, size, internalize);
53 std::memcpy(buffer_ptr, host_ptr, size); 72 }
54 buffer_ptr += size;
55 buffer_offset += size;
56 73
57 const GLuint buffer = stream_buffer.GetHandle(); 74 if (entry->GetSize() < size) {
58 if (cache) { 75 GrowBuffer(entry, size);
59 const VAddr cpu_addr = *memory_manager.GpuToCpuAddress(gpu_addr);
60 Register(std::make_shared<CachedBufferEntry>(cpu_addr, host_ptr, size, alignment, buffer,
61 uploaded_offset));
62 } 76 }
77 return {entry->GetBuffer(), CachedBufferOffset};
78}
63 79
64 return {buffer, uploaded_offset}; 80OGLBufferCache::BufferInfo OGLBufferCache::UploadHostMemory(const void* raw_pointer,
81 std::size_t size,
82 std::size_t alignment) {
83 return StreamBufferUpload(raw_pointer, size, alignment);
65} 84}
66 85
67std::pair<GLuint, GLintptr> OGLBufferCache::UploadHostMemory(const void* raw_pointer, 86bool OGLBufferCache::Map(std::size_t max_size) {
68 std::size_t size, 87 const auto max_size_ = static_cast<GLsizeiptr>(max_size);
69 std::size_t alignment) { 88 bool invalidate;
70 std::lock_guard lock{mutex}; 89 std::tie(buffer_ptr, buffer_offset_base, invalidate) = stream_buffer.Map(max_size_, 4);
90 buffer_offset = buffer_offset_base;
91 return invalidate;
92}
93
94void OGLBufferCache::Unmap() {
95 stream_buffer.Unmap(buffer_offset - buffer_offset_base);
96}
97
98OGLBufferCache::BufferInfo OGLBufferCache::StreamBufferUpload(const void* raw_pointer,
99 std::size_t size,
100 std::size_t alignment) {
71 AlignBuffer(alignment); 101 AlignBuffer(alignment);
72 std::memcpy(buffer_ptr, raw_pointer, size);
73 const GLintptr uploaded_offset = buffer_offset; 102 const GLintptr uploaded_offset = buffer_offset;
103 std::memcpy(buffer_ptr, raw_pointer, size);
74 104
75 buffer_ptr += size; 105 buffer_ptr += size;
76 buffer_offset += size; 106 buffer_offset += size;
77 return {stream_buffer.GetHandle(), uploaded_offset}; 107 return {stream_buffer.GetHandle(), uploaded_offset};
78} 108}
79 109
80bool OGLBufferCache::Map(std::size_t max_size) { 110OGLBufferCache::BufferInfo OGLBufferCache::FixedBufferUpload(GPUVAddr gpu_addr, u8* host_ptr,
81 bool invalidate; 111 std::size_t size, bool internalize) {
82 std::tie(buffer_ptr, buffer_offset_base, invalidate) = 112 if (internalize) {
83 stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4); 113 internalized_entries.emplace(ToCacheAddr(host_ptr));
84 buffer_offset = buffer_offset_base; 114 }
115 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
116 const auto cpu_addr = *memory_manager.GpuToCpuAddress(gpu_addr);
117 auto entry = GetUncachedBuffer(cpu_addr, host_ptr);
118 entry->SetSize(size);
119 entry->SetInternalState(internalize);
120 Register(entry);
121
122 if (entry->GetCapacity() < size) {
123 entry->SetCapacity(CreateBuffer(size, GL_STATIC_DRAW), size);
124 }
125 glNamedBufferSubData(entry->GetBuffer(), 0, static_cast<GLintptr>(size), host_ptr);
126 return {entry->GetBuffer(), CachedBufferOffset};
127}
128
129void OGLBufferCache::GrowBuffer(std::shared_ptr<CachedBufferEntry>& entry, std::size_t new_size) {
130 const auto old_size = static_cast<GLintptr>(entry->GetSize());
131 if (entry->GetCapacity() < new_size) {
132 const auto old_buffer = entry->GetBuffer();
133 OGLBuffer new_buffer = CreateBuffer(new_size, GL_STATIC_COPY);
85 134
86 if (invalidate) { 135 // Copy bits from the old buffer to the new buffer.
87 InvalidateAll(); 136 glCopyNamedBufferSubData(old_buffer, new_buffer.handle, 0, 0, old_size);
137 entry->SetCapacity(std::move(new_buffer), new_size);
88 } 138 }
89 return invalidate; 139 // Upload the new bits.
140 const auto size_diff = static_cast<GLintptr>(new_size - old_size);
141 glNamedBufferSubData(entry->GetBuffer(), old_size, size_diff, entry->GetHostPtr() + old_size);
142
143 // Update entry's size in the object and in the cache.
144 entry->SetSize(new_size);
145 Unregister(entry);
146 Register(entry);
90} 147}
91 148
92void OGLBufferCache::Unmap() { 149std::shared_ptr<CachedBufferEntry> OGLBufferCache::GetUncachedBuffer(VAddr cpu_addr, u8* host_ptr) {
93 stream_buffer.Unmap(buffer_offset - buffer_offset_base); 150 if (auto entry = TryGetReservedBuffer(host_ptr); entry) {
151 return entry;
152 }
153 return std::make_shared<CachedBufferEntry>(cpu_addr, host_ptr);
154}
155
156std::shared_ptr<CachedBufferEntry> OGLBufferCache::TryGetReservedBuffer(u8* host_ptr) {
157 const auto it = buffer_reserve.find(ToCacheAddr(host_ptr));
158 if (it == buffer_reserve.end()) {
159 return {};
160 }
161 auto& reserve = it->second;
162 auto entry = reserve.back();
163 reserve.pop_back();
164 return entry;
165}
166
167void OGLBufferCache::ReserveBuffer(std::shared_ptr<CachedBufferEntry> entry) {
168 buffer_reserve[entry->GetCacheAddr()].push_back(std::move(entry));
94} 169}
95 170
96void OGLBufferCache::AlignBuffer(std::size_t alignment) { 171void OGLBufferCache::AlignBuffer(std::size_t alignment) {
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 4a055035a..00bc6008a 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -5,9 +5,12 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <map>
8#include <memory> 9#include <memory>
9#include <tuple> 10#include <tuple>
11#include <unordered_set>
10#include <utility> 12#include <utility>
13#include <vector>
11 14
12#include "common/common_types.h" 15#include "common/common_types.h"
13#include "video_core/rasterizer_cache.h" 16#include "video_core/rasterizer_cache.h"
@@ -20,8 +23,7 @@ class RasterizerOpenGL;
20 23
21class CachedBufferEntry final : public RasterizerCacheObject { 24class CachedBufferEntry final : public RasterizerCacheObject {
22public: 25public:
23 explicit CachedBufferEntry(VAddr cpu_addr, u8* host_ptr, std::size_t size, 26 explicit CachedBufferEntry(VAddr cpu_addr, u8* host_ptr);
24 std::size_t alignment, GLuint buffer, GLintptr offset);
25 27
26 VAddr GetCpuAddr() const override { 28 VAddr GetCpuAddr() const override {
27 return cpu_addr; 29 return cpu_addr;
@@ -35,55 +37,87 @@ public:
35 return size; 37 return size;
36 } 38 }
37 39
38 std::size_t GetAlignment() const { 40 std::size_t GetCapacity() const {
39 return alignment; 41 return capacity;
42 }
43
44 bool IsInternalized() const {
45 return is_internal;
40 } 46 }
41 47
42 GLuint GetBuffer() const { 48 GLuint GetBuffer() const {
43 return buffer; 49 return buffer.handle;
50 }
51
52 void SetSize(std::size_t new_size) {
53 size = new_size;
54 }
55
56 void SetInternalState(bool is_internal_) {
57 is_internal = is_internal_;
44 } 58 }
45 59
46 GLintptr GetOffset() const { 60 void SetCapacity(OGLBuffer&& new_buffer, std::size_t new_capacity) {
47 return offset; 61 capacity = new_capacity;
62 buffer = std::move(new_buffer);
48 } 63 }
49 64
50private: 65private:
51 VAddr cpu_addr{}; 66 VAddr cpu_addr{};
52 std::size_t size{}; 67 std::size_t size{};
53 std::size_t alignment{}; 68 std::size_t capacity{};
54 69 bool is_internal{};
55 GLuint buffer{}; 70 OGLBuffer buffer;
56 GLintptr offset{};
57}; 71};
58 72
59class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { 73class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
74 using BufferInfo = std::pair<GLuint, GLintptr>;
75
60public: 76public:
61 explicit OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size); 77 explicit OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size);
78 ~OGLBufferCache();
79
80 void Unregister(const std::shared_ptr<CachedBufferEntry>& entry) override;
62 81
63 /// Uploads data from a guest GPU address. Returns the OpenGL buffer where it's located and its 82 /// Uploads data from a guest GPU address. Returns the OpenGL buffer where it's located and its
64 /// offset. 83 /// offset.
65 std::pair<GLuint, GLintptr> UploadMemory(GPUVAddr gpu_addr, std::size_t size, 84 BufferInfo UploadMemory(GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4,
66 std::size_t alignment = 4, bool cache = true); 85 bool internalize = false);
67 86
68 /// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset. 87 /// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset.
69 std::pair<GLuint, GLintptr> UploadHostMemory(const void* raw_pointer, std::size_t size, 88 BufferInfo UploadHostMemory(const void* raw_pointer, std::size_t size,
70 std::size_t alignment = 4); 89 std::size_t alignment = 4);
71 90
72 bool Map(std::size_t max_size); 91 bool Map(std::size_t max_size);
73 void Unmap(); 92 void Unmap();
74 93
75protected: 94protected:
76 void AlignBuffer(std::size_t alignment);
77
78 // We do not have to flush this cache as things in it are never modified by us. 95 // We do not have to flush this cache as things in it are never modified by us.
79 void FlushObjectInner(const std::shared_ptr<CachedBufferEntry>& object) override {} 96 void FlushObjectInner(const std::shared_ptr<CachedBufferEntry>& object) override {}
80 97
81private: 98private:
82 OGLStreamBuffer stream_buffer; 99 BufferInfo StreamBufferUpload(const void* raw_pointer, std::size_t size, std::size_t alignment);
100
101 BufferInfo FixedBufferUpload(GPUVAddr gpu_addr, u8* host_ptr, std::size_t size,
102 bool internalize);
103
104 void GrowBuffer(std::shared_ptr<CachedBufferEntry>& entry, std::size_t new_size);
105
106 std::shared_ptr<CachedBufferEntry> GetUncachedBuffer(VAddr cpu_addr, u8* host_ptr);
107
108 std::shared_ptr<CachedBufferEntry> TryGetReservedBuffer(u8* host_ptr);
109
110 void ReserveBuffer(std::shared_ptr<CachedBufferEntry> entry);
111
112 void AlignBuffer(std::size_t alignment);
83 113
84 u8* buffer_ptr = nullptr; 114 u8* buffer_ptr = nullptr;
85 GLintptr buffer_offset = 0; 115 GLintptr buffer_offset = 0;
86 GLintptr buffer_offset_base = 0; 116 GLintptr buffer_offset_base = 0;
117
118 OGLStreamBuffer stream_buffer;
119 std::unordered_set<CacheAddr> internalized_entries;
120 std::unordered_map<CacheAddr, std::vector<std::shared_ptr<CachedBufferEntry>>> buffer_reserve;
87}; 121};
88 122
89} // namespace OpenGL 123} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index d694dacfb..e216163e1 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -790,7 +790,7 @@ void RasterizerOpenGL::SetupConstBuffer(const Tegra::Engines::ConstBufferInfo& b
790 size = Common::AlignUp(size, sizeof(GLvec4)); 790 size = Common::AlignUp(size, sizeof(GLvec4));
791 ASSERT_MSG(size <= MaxConstbufferSize, "Constant buffer is too big"); 791 ASSERT_MSG(size <= MaxConstbufferSize, "Constant buffer is too big");
792 792
793 const std::size_t alignment = device.GetUniformBufferAlignment(); 793 const auto alignment = device.GetUniformBufferAlignment();
794 const auto [cbuf, offset] = buffer_cache.UploadMemory(buffer.address, size, alignment); 794 const auto [cbuf, offset] = buffer_cache.UploadMemory(buffer.address, size, alignment);
795 bind_ubo_pushbuffer.Push(cbuf, offset, size); 795 bind_ubo_pushbuffer.Push(cbuf, offset, size);
796} 796}