summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/rasterizer_interface.h3
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp189
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h115
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp40
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp4
-rw-r--r--src/video_core/renderer_opengl/utils.cpp17
-rw-r--r--src/video_core/renderer_opengl/utils.h14
8 files changed, 92 insertions, 291 deletions
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 5ee4f8e8e..2b7367568 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -47,6 +47,9 @@ public:
47 /// and invalidated 47 /// and invalidated
48 virtual void FlushAndInvalidateRegion(CacheAddr addr, u64 size) = 0; 48 virtual void FlushAndInvalidateRegion(CacheAddr addr, u64 size) = 0;
49 49
50 /// Notify rasterizer that a frame is about to finish
51 virtual void TickFrame() = 0;
52
50 /// Attempt to use a faster method to perform a surface copy 53 /// Attempt to use a faster method to perform a surface copy
51 virtual bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 54 virtual bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
52 const Tegra::Engines::Fermi2D::Regs::Surface& dst, 55 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index fb3aedd07..2a9b523f5 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -2,192 +2,57 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6#include <memory> 5#include <memory>
7#include <utility>
8 6
9#include "common/alignment.h" 7#include <glad/glad.h>
8
10#include "common/assert.h" 9#include "common/assert.h"
11#include "core/core.h"
12#include "video_core/memory_manager.h"
13#include "video_core/renderer_opengl/gl_buffer_cache.h" 10#include "video_core/renderer_opengl/gl_buffer_cache.h"
14#include "video_core/renderer_opengl/gl_rasterizer.h" 11#include "video_core/renderer_opengl/gl_rasterizer.h"
15#include "video_core/renderer_opengl/gl_resource_manager.h" 12#include "video_core/renderer_opengl/gl_resource_manager.h"
16 13
17namespace OpenGL { 14namespace OpenGL {
18 15
19namespace { 16OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
17 std::size_t stream_size)
18 : VideoCommon::BufferCache<OGLBuffer, GLuint, OGLStreamBuffer>{
19 rasterizer, system, std::make_unique<OGLStreamBuffer>(stream_size, true)} {}
20 20
21constexpr GLuint EmptyBuffer = 0; 21OGLBufferCache::~OGLBufferCache() = default;
22constexpr GLintptr CachedBufferOffset = 0;
23 22
24OGLBuffer CreateBuffer(std::size_t size, GLenum usage) { 23OGLBuffer OGLBufferCache::CreateBuffer(std::size_t size) {
25 OGLBuffer buffer; 24 OGLBuffer buffer;
26 buffer.Create(); 25 buffer.Create();
27 glNamedBufferData(buffer.handle, size, nullptr, usage); 26 glNamedBufferData(buffer.handle, static_cast<GLsizeiptr>(size), nullptr, GL_DYNAMIC_DRAW);
28 return buffer; 27 return buffer;
29} 28}
30 29
31} // Anonymous namespace 30const GLuint* OGLBufferCache::ToHandle(const OGLBuffer& buffer) {
32 31 return &buffer.handle;
33CachedBufferEntry::CachedBufferEntry(VAddr cpu_addr, u8* host_ptr)
34 : RasterizerCacheObject{host_ptr}, host_ptr{host_ptr}, cpu_addr{cpu_addr} {}
35
36OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system, std::size_t size)
37 : RasterizerCache{rasterizer}, system{system}, stream_buffer(size, true) {}
38
39OGLBufferCache::~OGLBufferCache() = default;
40
41void OGLBufferCache::Unregister(const std::shared_ptr<CachedBufferEntry>& entry) {
42 std::lock_guard lock{mutex};
43
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 bool is_written) {
54 std::lock_guard lock{mutex};
55
56 auto& memory_manager = system.GPU().MemoryManager();
57 const auto host_ptr{memory_manager.GetPointer(gpu_addr)};
58 const auto cache_addr{ToCacheAddr(host_ptr)};
59 if (!host_ptr) {
60 return {EmptyBuffer, 0};
61 }
62
63 // Cache management is a big overhead, so only cache entries with a given size.
64 // TODO: Figure out which size is the best for given games.
65 if (!internalize && size < 0x800 &&
66 internalized_entries.find(cache_addr) == internalized_entries.end()) {
67 return StreamBufferUpload(host_ptr, size, alignment);
68 }
69
70 auto entry = TryGet(host_ptr);
71 if (!entry) {
72 return FixedBufferUpload(gpu_addr, host_ptr, size, internalize, is_written);
73 }
74
75 if (entry->GetSize() < size) {
76 GrowBuffer(entry, size);
77 }
78 if (is_written) {
79 entry->MarkAsModified(true, *this);
80 }
81 return {entry->GetBuffer(), CachedBufferOffset};
82}
83
84OGLBufferCache::BufferInfo OGLBufferCache::UploadHostMemory(const void* raw_pointer,
85 std::size_t size,
86 std::size_t alignment) {
87 std::lock_guard lock{mutex};
88 return StreamBufferUpload(raw_pointer, size, alignment);
89}
90
91bool OGLBufferCache::Map(std::size_t max_size) {
92 const auto max_size_ = static_cast<GLsizeiptr>(max_size);
93 bool invalidate;
94 std::tie(buffer_ptr, buffer_offset_base, invalidate) = stream_buffer.Map(max_size_, 4);
95 buffer_offset = buffer_offset_base;
96 return invalidate;
97}
98
99void OGLBufferCache::Unmap() {
100 stream_buffer.Unmap(buffer_offset - buffer_offset_base);
101}
102
103void OGLBufferCache::FlushObjectInner(const std::shared_ptr<CachedBufferEntry>& entry) {
104 glGetNamedBufferSubData(entry->GetBuffer(), 0, entry->GetSize(), entry->GetWritableHostPtr());
105}
106
107OGLBufferCache::BufferInfo OGLBufferCache::StreamBufferUpload(const void* raw_pointer,
108 std::size_t size,
109 std::size_t alignment) {
110 AlignBuffer(alignment);
111 const GLintptr uploaded_offset = buffer_offset;
112 std::memcpy(buffer_ptr, raw_pointer, size);
113
114 buffer_ptr += size;
115 buffer_offset += size;
116 return {stream_buffer.GetHandle(), uploaded_offset};
117}
118
119OGLBufferCache::BufferInfo OGLBufferCache::FixedBufferUpload(GPUVAddr gpu_addr, u8* host_ptr,
120 std::size_t size, bool internalize,
121 bool is_written) {
122 auto& memory_manager = system.GPU().MemoryManager();
123 const auto cpu_addr = *memory_manager.GpuToCpuAddress(gpu_addr);
124 auto entry = GetUncachedBuffer(cpu_addr, host_ptr);
125 entry->SetSize(size);
126 entry->SetInternalState(internalize);
127 Register(entry);
128
129 if (internalize) {
130 internalized_entries.emplace(ToCacheAddr(host_ptr));
131 }
132 if (is_written) {
133 entry->MarkAsModified(true, *this);
134 }
135
136 if (entry->GetCapacity() < size) {
137 entry->SetCapacity(CreateBuffer(size, GL_STATIC_DRAW), size);
138 }
139 glNamedBufferSubData(entry->GetBuffer(), 0, static_cast<GLintptr>(size), host_ptr);
140 return {entry->GetBuffer(), CachedBufferOffset};
141}
142
143void OGLBufferCache::GrowBuffer(std::shared_ptr<CachedBufferEntry>& entry, std::size_t new_size) {
144 const auto old_size = static_cast<GLintptr>(entry->GetSize());
145 if (entry->GetCapacity() < new_size) {
146 const auto old_buffer = entry->GetBuffer();
147 OGLBuffer new_buffer = CreateBuffer(new_size, GL_STATIC_COPY);
148
149 // Copy bits from the old buffer to the new buffer.
150 glCopyNamedBufferSubData(old_buffer, new_buffer.handle, 0, 0, old_size);
151 entry->SetCapacity(std::move(new_buffer), new_size);
152 }
153 // Upload the new bits.
154 const auto size_diff = static_cast<GLintptr>(new_size - old_size);
155 glNamedBufferSubData(entry->GetBuffer(), old_size, size_diff, entry->GetHostPtr() + old_size);
156
157 // Update entry's size in the object and in the cache.
158 entry->SetSize(new_size);
159 Unregister(entry);
160 Register(entry);
161} 32}
162 33
163std::shared_ptr<CachedBufferEntry> OGLBufferCache::GetUncachedBuffer(VAddr cpu_addr, u8* host_ptr) { 34const GLuint* OGLBufferCache::GetEmptyBuffer(std::size_t) {
164 if (auto entry = TryGetReservedBuffer(host_ptr)) { 35 static const GLuint null_buffer = 0;
165 return entry; 36 return &null_buffer;
166 }
167 return std::make_shared<CachedBufferEntry>(cpu_addr, host_ptr);
168} 37}
169 38
170std::shared_ptr<CachedBufferEntry> OGLBufferCache::TryGetReservedBuffer(u8* host_ptr) { 39void OGLBufferCache::UploadBufferData(const OGLBuffer& buffer, std::size_t offset, std::size_t size,
171 const auto it = buffer_reserve.find(ToCacheAddr(host_ptr)); 40 const u8* data) {
172 if (it == buffer_reserve.end()) { 41 glNamedBufferSubData(buffer.handle, static_cast<GLintptr>(offset),
173 return {}; 42 static_cast<GLsizeiptr>(size), data);
174 }
175 auto& reserve = it->second;
176 auto entry = reserve.back();
177 reserve.pop_back();
178 return entry;
179} 43}
180 44
181void OGLBufferCache::ReserveBuffer(std::shared_ptr<CachedBufferEntry> entry) { 45void OGLBufferCache::DownloadBufferData(const OGLBuffer& buffer, std::size_t offset,
182 buffer_reserve[entry->GetCacheAddr()].push_back(std::move(entry)); 46 std::size_t size, u8* data) {
47 glGetNamedBufferSubData(buffer.handle, static_cast<GLintptr>(offset),
48 static_cast<GLsizeiptr>(size), data);
183} 49}
184 50
185void OGLBufferCache::AlignBuffer(std::size_t alignment) { 51void OGLBufferCache::CopyBufferData(const OGLBuffer& src, const OGLBuffer& dst,
186 // Align the offset, not the mapped pointer 52 std::size_t src_offset, std::size_t dst_offset,
187 const GLintptr offset_aligned = 53 std::size_t size) {
188 static_cast<GLintptr>(Common::AlignUp(static_cast<std::size_t>(buffer_offset), alignment)); 54 glCopyNamedBufferSubData(src.handle, dst.handle, static_cast<GLintptr>(src_offset),
189 buffer_ptr += offset_aligned - buffer_offset; 55 static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size));
190 buffer_offset = offset_aligned;
191} 56}
192 57
193} // namespace OpenGL 58} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 19d643e41..3befdc6ab 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -4,15 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8#include <map>
9#include <memory> 7#include <memory>
10#include <tuple>
11#include <unordered_set>
12#include <utility>
13#include <vector>
14 8
15#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/buffer_cache.h"
16#include "video_core/rasterizer_cache.h" 11#include "video_core/rasterizer_cache.h"
17#include "video_core/renderer_opengl/gl_resource_manager.h" 12#include "video_core/renderer_opengl/gl_resource_manager.h"
18#include "video_core/renderer_opengl/gl_stream_buffer.h" 13#include "video_core/renderer_opengl/gl_stream_buffer.h"
@@ -23,112 +18,30 @@ class System;
23 18
24namespace OpenGL { 19namespace OpenGL {
25 20
21class OGLStreamBuffer;
26class RasterizerOpenGL; 22class RasterizerOpenGL;
27 23
28class CachedBufferEntry final : public RasterizerCacheObject { 24class OGLBufferCache final : public VideoCommon::BufferCache<OGLBuffer, GLuint, OGLStreamBuffer> {
29public: 25public:
30 explicit CachedBufferEntry(VAddr cpu_addr, u8* host_ptr); 26 explicit OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
31 27 std::size_t stream_size);
32 VAddr GetCpuAddr() const override {
33 return cpu_addr;
34 }
35
36 std::size_t GetSizeInBytes() const override {
37 return size;
38 }
39
40 u8* GetWritableHostPtr() const {
41 return host_ptr;
42 }
43
44 std::size_t GetSize() const {
45 return size;
46 }
47
48 std::size_t GetCapacity() const {
49 return capacity;
50 }
51
52 bool IsInternalized() const {
53 return is_internal;
54 }
55
56 GLuint GetBuffer() const {
57 return buffer.handle;
58 }
59
60 void SetSize(std::size_t new_size) {
61 size = new_size;
62 }
63
64 void SetInternalState(bool is_internal_) {
65 is_internal = is_internal_;
66 }
67
68 void SetCapacity(OGLBuffer&& new_buffer, std::size_t new_capacity) {
69 capacity = new_capacity;
70 buffer = std::move(new_buffer);
71 }
72
73private:
74 u8* host_ptr{};
75 VAddr cpu_addr{};
76 std::size_t size{};
77 std::size_t capacity{};
78 bool is_internal{};
79 OGLBuffer buffer;
80};
81
82class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
83 using BufferInfo = std::pair<GLuint, GLintptr>;
84
85public:
86 explicit OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system, std::size_t size);
87 ~OGLBufferCache(); 28 ~OGLBufferCache();
88 29
89 void Unregister(const std::shared_ptr<CachedBufferEntry>& entry) override;
90
91 /// Uploads data from a guest GPU address. Returns the OpenGL buffer where it's located and its
92 /// offset.
93 BufferInfo UploadMemory(GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4,
94 bool internalize = false, bool is_written = false);
95
96 /// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset.
97 BufferInfo UploadHostMemory(const void* raw_pointer, std::size_t size,
98 std::size_t alignment = 4);
99
100 bool Map(std::size_t max_size);
101 void Unmap();
102
103protected: 30protected:
104 // We do not have to flush this cache as things in it are never modified by us. 31 OGLBuffer CreateBuffer(std::size_t size) override;
105 void FlushObjectInner(const std::shared_ptr<CachedBufferEntry>& entry) override;
106
107private:
108 BufferInfo StreamBufferUpload(const void* raw_pointer, std::size_t size, std::size_t alignment);
109
110 BufferInfo FixedBufferUpload(GPUVAddr gpu_addr, u8* host_ptr, std::size_t size,
111 bool internalize, bool is_written);
112
113 void GrowBuffer(std::shared_ptr<CachedBufferEntry>& entry, std::size_t new_size);
114
115 std::shared_ptr<CachedBufferEntry> GetUncachedBuffer(VAddr cpu_addr, u8* host_ptr);
116
117 std::shared_ptr<CachedBufferEntry> TryGetReservedBuffer(u8* host_ptr);
118 32
119 void ReserveBuffer(std::shared_ptr<CachedBufferEntry> entry); 33 const GLuint* ToHandle(const OGLBuffer& buffer) override;
120 34
121 void AlignBuffer(std::size_t alignment); 35 const GLuint* GetEmptyBuffer(std::size_t) override;
122 36
123 Core::System& system; 37 void UploadBufferData(const OGLBuffer& buffer, std::size_t offset, std::size_t size,
38 const u8* data) override;
124 39
125 u8* buffer_ptr = nullptr; 40 void DownloadBufferData(const OGLBuffer& buffer, std::size_t offset, std::size_t size,
126 GLintptr buffer_offset = 0; 41 u8* data) override;
127 GLintptr buffer_offset_base = 0;
128 42
129 OGLStreamBuffer stream_buffer; 43 void CopyBufferData(const OGLBuffer& src, const OGLBuffer& dst, std::size_t src_offset,
130 std::unordered_set<CacheAddr> internalized_entries; 44 std::size_t dst_offset, std::size_t size) override;
131 std::unordered_map<CacheAddr, std::vector<std::shared_ptr<CachedBufferEntry>>> buffer_reserve;
132}; 45};
133 46
134} // namespace OpenGL 47} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 35ba84235..b57d60856 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -198,7 +198,8 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) {
198 const auto [vertex_buffer, vertex_buffer_offset] = buffer_cache.UploadMemory(start, size); 198 const auto [vertex_buffer, vertex_buffer_offset] = buffer_cache.UploadMemory(start, size);
199 199
200 // Bind the vertex array to the buffer at the current offset. 200 // Bind the vertex array to the buffer at the current offset.
201 glVertexArrayVertexBuffer(vao, index, vertex_buffer, vertex_buffer_offset, 201 // FIXME(Rodrigo): This dereferenced pointer might be invalidated in future uploads.
202 glVertexArrayVertexBuffer(vao, index, *vertex_buffer, vertex_buffer_offset,
202 vertex_array.stride); 203 vertex_array.stride);
203 204
204 if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) { 205 if (regs.instanced_arrays.IsInstancingEnabled(index) && vertex_array.divisor != 0) {
@@ -221,7 +222,8 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer(GLuint vao) {
221 const auto& regs = system.GPU().Maxwell3D().regs; 222 const auto& regs = system.GPU().Maxwell3D().regs;
222 const std::size_t size = CalculateIndexBufferSize(); 223 const std::size_t size = CalculateIndexBufferSize();
223 const auto [buffer, offset] = buffer_cache.UploadMemory(regs.index_array.IndexStart(), size); 224 const auto [buffer, offset] = buffer_cache.UploadMemory(regs.index_array.IndexStart(), size);
224 glVertexArrayElementBuffer(vao, buffer); 225 // FIXME(Rodrigo): This dereferenced pointer might be invalidated in future uploads.
226 glVertexArrayElementBuffer(vao, *buffer);
225 return offset; 227 return offset;
226} 228}
227 229
@@ -255,10 +257,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
255 BaseBindings base_bindings; 257 BaseBindings base_bindings;
256 std::array<bool, Maxwell::NumClipDistances> clip_distances{}; 258 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
257 259
258 // Prepare packed bindings
259 bind_ubo_pushbuffer.Setup(base_bindings.cbuf);
260 bind_ssbo_pushbuffer.Setup(base_bindings.gmem);
261
262 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 260 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
263 const auto& shader_config = gpu.regs.shader_config[index]; 261 const auto& shader_config = gpu.regs.shader_config[index];
264 const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)}; 262 const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)};
@@ -328,9 +326,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
328 base_bindings = next_bindings; 326 base_bindings = next_bindings;
329 } 327 }
330 328
331 bind_ubo_pushbuffer.Bind();
332 bind_ssbo_pushbuffer.Bind();
333
334 SyncClipEnabled(clip_distances); 329 SyncClipEnabled(clip_distances);
335 330
336 gpu.dirty_flags.shaders = false; 331 gpu.dirty_flags.shaders = false;
@@ -644,11 +639,8 @@ void RasterizerOpenGL::DrawArrays() {
644 buffer_size += 639 buffer_size +=
645 Maxwell::MaxConstBuffers * (MaxConstbufferSize + device.GetUniformBufferAlignment()); 640 Maxwell::MaxConstBuffers * (MaxConstbufferSize + device.GetUniformBufferAlignment());
646 641
647 const bool invalidate = buffer_cache.Map(buffer_size); 642 // Prepare the vertex array.
648 if (invalidate) { 643 buffer_cache.Map(buffer_size);
649 // As all cached buffers are invalidated, we need to recheck their state.
650 gpu.dirty_flags.vertex_array.set();
651 }
652 644
653 // Prepare vertex array format. 645 // Prepare vertex array format.
654 const GLuint vao = SetupVertexFormat(); 646 const GLuint vao = SetupVertexFormat();
@@ -660,6 +652,10 @@ void RasterizerOpenGL::DrawArrays() {
660 // Setup draw parameters. It will automatically choose what glDraw* method to use. 652 // Setup draw parameters. It will automatically choose what glDraw* method to use.
661 const DrawParameters params = SetupDraw(index_buffer_offset); 653 const DrawParameters params = SetupDraw(index_buffer_offset);
662 654
655 // Prepare packed bindings.
656 bind_ubo_pushbuffer.Setup(0);
657 bind_ssbo_pushbuffer.Setup(0);
658
663 // Setup shaders and their used resources. 659 // Setup shaders and their used resources.
664 texture_cache.GuardSamplers(true); 660 texture_cache.GuardSamplers(true);
665 SetupShaders(params.primitive_mode); 661 SetupShaders(params.primitive_mode);
@@ -667,7 +663,17 @@ void RasterizerOpenGL::DrawArrays() {
667 663
668 ConfigureFramebuffers(state); 664 ConfigureFramebuffers(state);
669 665
670 buffer_cache.Unmap(); 666 // Signal the buffer cache that we are not going to upload more things.
667 const bool invalidate = buffer_cache.Unmap();
668
669 // Now that we are no longer uploading data, we can safely bind the buffers to OpenGL.
670 bind_ubo_pushbuffer.Bind();
671 bind_ssbo_pushbuffer.Bind();
672
673 if (invalidate) {
674 // As all cached buffers are invalidated, we need to recheck their state.
675 gpu.dirty_flags.vertex_array.set();
676 }
671 677
672 shader_program_manager->ApplyTo(state); 678 shader_program_manager->ApplyTo(state);
673 state.Apply(); 679 state.Apply();
@@ -709,6 +715,10 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(CacheAddr addr, u64 size) {
709 InvalidateRegion(addr, size); 715 InvalidateRegion(addr, size);
710} 716}
711 717
718void RasterizerOpenGL::TickFrame() {
719 buffer_cache.TickFrame();
720}
721
712bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 722bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
713 const Tegra::Engines::Fermi2D::Regs::Surface& dst, 723 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
714 const Tegra::Engines::Fermi2D::Config& copy_config) { 724 const Tegra::Engines::Fermi2D::Config& copy_config) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index bc988727b..7067ad5b4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -62,6 +62,7 @@ public:
62 void FlushRegion(CacheAddr addr, u64 size) override; 62 void FlushRegion(CacheAddr addr, u64 size) override;
63 void InvalidateRegion(CacheAddr addr, u64 size) override; 63 void InvalidateRegion(CacheAddr addr, u64 size) override;
64 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override; 64 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override;
65 void TickFrame() override;
65 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 66 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
66 const Tegra::Engines::Fermi2D::Regs::Surface& dst, 67 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
67 const Tegra::Engines::Fermi2D::Config& copy_config) override; 68 const Tegra::Engines::Fermi2D::Config& copy_config) override;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index b142521ec..9ecdddb0d 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -101,7 +101,6 @@ RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::Syst
101 101
102RendererOpenGL::~RendererOpenGL() = default; 102RendererOpenGL::~RendererOpenGL() = default;
103 103
104/// Swap buffers (render frame)
105void RendererOpenGL::SwapBuffers( 104void RendererOpenGL::SwapBuffers(
106 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { 105 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) {
107 106
@@ -130,6 +129,8 @@ void RendererOpenGL::SwapBuffers(
130 129
131 DrawScreen(render_window.GetFramebufferLayout()); 130 DrawScreen(render_window.GetFramebufferLayout());
132 131
132 rasterizer->TickFrame();
133
133 render_window.SwapBuffers(); 134 render_window.SwapBuffers();
134 } 135 }
135 136
@@ -262,7 +263,6 @@ void RendererOpenGL::CreateRasterizer() {
262 if (rasterizer) { 263 if (rasterizer) {
263 return; 264 return;
264 } 265 }
265 // Initialize sRGB Usage
266 OpenGLState::ClearsRGBUsed(); 266 OpenGLState::ClearsRGBUsed();
267 rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info); 267 rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info);
268} 268}
diff --git a/src/video_core/renderer_opengl/utils.cpp b/src/video_core/renderer_opengl/utils.cpp
index 68c36988d..22eefa1d7 100644
--- a/src/video_core/renderer_opengl/utils.cpp
+++ b/src/video_core/renderer_opengl/utils.cpp
@@ -19,23 +19,30 @@ BindBuffersRangePushBuffer::~BindBuffersRangePushBuffer() = default;
19 19
20void BindBuffersRangePushBuffer::Setup(GLuint first_) { 20void BindBuffersRangePushBuffer::Setup(GLuint first_) {
21 first = first_; 21 first = first_;
22 buffers.clear(); 22 buffer_pointers.clear();
23 offsets.clear(); 23 offsets.clear();
24 sizes.clear(); 24 sizes.clear();
25} 25}
26 26
27void BindBuffersRangePushBuffer::Push(GLuint buffer, GLintptr offset, GLsizeiptr size) { 27void BindBuffersRangePushBuffer::Push(const GLuint* buffer, GLintptr offset, GLsizeiptr size) {
28 buffers.push_back(buffer); 28 buffer_pointers.push_back(buffer);
29 offsets.push_back(offset); 29 offsets.push_back(offset);
30 sizes.push_back(size); 30 sizes.push_back(size);
31} 31}
32 32
33void BindBuffersRangePushBuffer::Bind() const { 33void BindBuffersRangePushBuffer::Bind() {
34 const std::size_t count{buffers.size()}; 34 // Ensure sizes are valid.
35 const std::size_t count{buffer_pointers.size()};
35 DEBUG_ASSERT(count == offsets.size() && count == sizes.size()); 36 DEBUG_ASSERT(count == offsets.size() && count == sizes.size());
36 if (count == 0) { 37 if (count == 0) {
37 return; 38 return;
38 } 39 }
40
41 // Dereference buffers.
42 buffers.resize(count);
43 std::transform(buffer_pointers.begin(), buffer_pointers.end(), buffers.begin(),
44 [](const GLuint* pointer) { return *pointer; });
45
39 glBindBuffersRange(target, first, static_cast<GLsizei>(count), buffers.data(), offsets.data(), 46 glBindBuffersRange(target, first, static_cast<GLsizei>(count), buffers.data(), offsets.data(),
40 sizes.data()); 47 sizes.data());
41} 48}
diff --git a/src/video_core/renderer_opengl/utils.h b/src/video_core/renderer_opengl/utils.h
index 4a752f3b4..d2a3d25d9 100644
--- a/src/video_core/renderer_opengl/utils.h
+++ b/src/video_core/renderer_opengl/utils.h
@@ -11,20 +11,22 @@
11 11
12namespace OpenGL { 12namespace OpenGL {
13 13
14class BindBuffersRangePushBuffer { 14class BindBuffersRangePushBuffer final {
15public: 15public:
16 BindBuffersRangePushBuffer(GLenum target); 16 explicit BindBuffersRangePushBuffer(GLenum target);
17 ~BindBuffersRangePushBuffer(); 17 ~BindBuffersRangePushBuffer();
18 18
19 void Setup(GLuint first_); 19 void Setup(GLuint first_);
20 20
21 void Push(GLuint buffer, GLintptr offset, GLsizeiptr size); 21 void Push(const GLuint* buffer, GLintptr offset, GLsizeiptr size);
22 22
23 void Bind() const; 23 void Bind();
24 24
25private: 25private:
26 GLenum target; 26 GLenum target{};
27 GLuint first; 27 GLuint first{};
28 std::vector<const GLuint*> buffer_pointers;
29
28 std::vector<GLuint> buffers; 30 std::vector<GLuint> buffers;
29 std::vector<GLintptr> offsets; 31 std::vector<GLintptr> offsets;
30 std::vector<GLsizeiptr> sizes; 32 std::vector<GLsizeiptr> sizes;