diff options
| author | 2019-05-27 20:50:11 -0300 | |
|---|---|---|
| committer | 2019-07-06 00:37:55 -0300 | |
| commit | 8155b12d3d8963ec4d8727614ffb522a33389cbf (patch) | |
| tree | 99ca355ef1c1bdecc990ddd76ac460e500133717 /src | |
| parent | gl_buffer_cache: Store in CachedBufferEntry the used buffer handle (diff) | |
| download | yuzu-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.cpp | 167 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_buffer_cache.h | 70 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 2 |
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 | ||
| 15 | namespace OpenGL { | 17 | namespace OpenGL { |
| 16 | 18 | ||
| 17 | CachedBufferEntry::CachedBufferEntry(VAddr cpu_addr, u8* host_ptr, std::size_t size, | 19 | namespace { |
| 18 | std::size_t alignment, GLuint buffer, GLintptr offset) | 20 | |
| 19 | : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr}, size{size}, alignment{alignment}, | 21 | constexpr GLuint EmptyBuffer = 0; |
| 20 | buffer{buffer}, offset{offset} {} | 22 | constexpr GLintptr CachedBufferOffset = 0; |
| 23 | |||
| 24 | OGLBuffer 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 | |||
| 33 | CachedBufferEntry::CachedBufferEntry(VAddr cpu_addr, u8* host_ptr) | ||
| 34 | : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr} {} | ||
| 21 | 35 | ||
| 22 | OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size) | 36 | OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size) |
| 23 | : RasterizerCache{rasterizer}, stream_buffer(size, true) {} | 37 | : RasterizerCache{rasterizer}, stream_buffer(size, true) {} |
| 24 | 38 | ||
| 25 | std::pair<GLuint, GLintptr> OGLBufferCache::UploadMemory(GPUVAddr gpu_addr, std::size_t size, | 39 | OGLBufferCache::~OGLBufferCache() = default; |
| 26 | std::size_t alignment, bool cache) { | 40 | |
| 41 | void 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 | |||
| 51 | OGLBufferCache::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}; | 80 | OGLBufferCache::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 | ||
| 67 | std::pair<GLuint, GLintptr> OGLBufferCache::UploadHostMemory(const void* raw_pointer, | 86 | bool 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 | |||
| 94 | void OGLBufferCache::Unmap() { | ||
| 95 | stream_buffer.Unmap(buffer_offset - buffer_offset_base); | ||
| 96 | } | ||
| 97 | |||
| 98 | OGLBufferCache::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 | ||
| 80 | bool OGLBufferCache::Map(std::size_t max_size) { | 110 | OGLBufferCache::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 | |||
| 129 | void 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 | ||
| 92 | void OGLBufferCache::Unmap() { | 149 | std::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 | |||
| 156 | std::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 | |||
| 167 | void OGLBufferCache::ReserveBuffer(std::shared_ptr<CachedBufferEntry> entry) { | ||
| 168 | buffer_reserve[entry->GetCacheAddr()].push_back(std::move(entry)); | ||
| 94 | } | 169 | } |
| 95 | 170 | ||
| 96 | void OGLBufferCache::AlignBuffer(std::size_t alignment) { | 171 | void 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 | ||
| 21 | class CachedBufferEntry final : public RasterizerCacheObject { | 24 | class CachedBufferEntry final : public RasterizerCacheObject { |
| 22 | public: | 25 | public: |
| 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 | ||
| 50 | private: | 65 | private: |
| 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 | ||
| 59 | class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { | 73 | class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { |
| 74 | using BufferInfo = std::pair<GLuint, GLintptr>; | ||
| 75 | |||
| 60 | public: | 76 | public: |
| 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 | ||
| 75 | protected: | 94 | protected: |
| 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 | ||
| 81 | private: | 98 | private: |
| 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 | } |