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_opengl/gl_stream_buffer.cpp182
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.h34
3 files changed, 218 insertions, 0 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 2f946e7be..7b26fe180 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -18,6 +18,8 @@ add_library(video_core STATIC
18 renderer_opengl/gl_shader_util.h 18 renderer_opengl/gl_shader_util.h
19 renderer_opengl/gl_state.cpp 19 renderer_opengl/gl_state.cpp
20 renderer_opengl/gl_state.h 20 renderer_opengl/gl_state.h
21 renderer_opengl/gl_stream_buffer.cpp
22 renderer_opengl/gl_stream_buffer.h
21 renderer_opengl/renderer_opengl.cpp 23 renderer_opengl/renderer_opengl.cpp
22 renderer_opengl/renderer_opengl.h 24 renderer_opengl/renderer_opengl.h
23 utils.h 25 utils.h
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
new file mode 100644
index 000000000..a2713e9f0
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -0,0 +1,182 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <deque>
6#include <vector>
7#include "common/alignment.h"
8#include "common/assert.h"
9#include "video_core/renderer_opengl/gl_state.h"
10#include "video_core/renderer_opengl/gl_stream_buffer.h"
11
12class OrphanBuffer : public OGLStreamBuffer {
13public:
14 explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {}
15 ~OrphanBuffer() override;
16
17private:
18 void Create(size_t size, size_t sync_subdivide) override;
19 void Release() override;
20
21 std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
22 void Unmap() override;
23
24 std::vector<u8> data;
25};
26
27class StorageBuffer : public OGLStreamBuffer {
28public:
29 explicit StorageBuffer(GLenum target) : OGLStreamBuffer(target) {}
30 ~StorageBuffer() override;
31
32private:
33 void Create(size_t size, size_t sync_subdivide) override;
34 void Release() override;
35
36 std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
37 void Unmap() override;
38
39 struct Fence {
40 OGLSync sync;
41 size_t offset;
42 };
43 std::deque<Fence> head;
44 std::deque<Fence> tail;
45
46 u8* mapped_ptr;
47};
48
49OGLStreamBuffer::OGLStreamBuffer(GLenum target) {
50 gl_target = target;
51}
52
53GLuint OGLStreamBuffer::GetHandle() const {
54 return gl_buffer.handle;
55}
56
57std::unique_ptr<OGLStreamBuffer> OGLStreamBuffer::MakeBuffer(bool storage_buffer, GLenum target) {
58 if (storage_buffer) {
59 return std::make_unique<StorageBuffer>(target);
60 }
61 return std::make_unique<OrphanBuffer>(target);
62}
63
64OrphanBuffer::~OrphanBuffer() {
65 Release();
66}
67
68void OrphanBuffer::Create(size_t size, size_t /*sync_subdivide*/) {
69 buffer_pos = 0;
70 buffer_size = size;
71 data.resize(buffer_size);
72
73 if (gl_buffer.handle == 0) {
74 gl_buffer.Create();
75 glBindBuffer(gl_target, gl_buffer.handle);
76 }
77
78 glBufferData(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, GL_STREAM_DRAW);
79}
80
81void OrphanBuffer::Release() {
82 gl_buffer.Release();
83}
84
85std::pair<u8*, GLintptr> OrphanBuffer::Map(size_t size, size_t alignment) {
86 buffer_pos = Common::AlignUp(buffer_pos, alignment);
87
88 if (buffer_pos + size > buffer_size) {
89 Create(std::max(buffer_size, size), 0);
90 }
91
92 mapped_size = size;
93 return std::make_pair(&data[buffer_pos], static_cast<GLintptr>(buffer_pos));
94}
95
96void OrphanBuffer::Unmap() {
97 glBufferSubData(gl_target, static_cast<GLintptr>(buffer_pos),
98 static_cast<GLsizeiptr>(mapped_size), &data[buffer_pos]);
99 buffer_pos += mapped_size;
100}
101
102StorageBuffer::~StorageBuffer() {
103 Release();
104}
105
106void StorageBuffer::Create(size_t size, size_t sync_subdivide) {
107 if (gl_buffer.handle != 0)
108 return;
109
110 buffer_pos = 0;
111 buffer_size = size;
112 buffer_sync_subdivide = std::max<size_t>(sync_subdivide, 1);
113
114 gl_buffer.Create();
115 glBindBuffer(gl_target, gl_buffer.handle);
116
117 glBufferStorage(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr,
118 GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
119 mapped_ptr = reinterpret_cast<u8*>(
120 glMapBufferRange(gl_target, 0, static_cast<GLsizeiptr>(buffer_size),
121 GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
122}
123
124void StorageBuffer::Release() {
125 if (gl_buffer.handle == 0)
126 return;
127
128 glUnmapBuffer(gl_target);
129
130 gl_buffer.Release();
131 head.clear();
132 tail.clear();
133}
134
135std::pair<u8*, GLintptr> StorageBuffer::Map(size_t size, size_t alignment) {
136 ASSERT(size <= buffer_size);
137
138 OGLSync sync;
139
140 buffer_pos = Common::AlignUp(buffer_pos, alignment);
141 size_t effective_offset = Common::AlignDown(buffer_pos, buffer_sync_subdivide);
142
143 if (!head.empty() &&
144 (effective_offset > head.back().offset || buffer_pos + size > buffer_size)) {
145 ASSERT(head.back().sync.handle == 0);
146 head.back().sync.Create();
147 }
148
149 if (buffer_pos + size > buffer_size) {
150 if (!tail.empty()) {
151 std::swap(sync, tail.back().sync);
152 tail.clear();
153 }
154 std::swap(tail, head);
155 buffer_pos = 0;
156 effective_offset = 0;
157 }
158
159 while (!tail.empty() && buffer_pos + size > tail.front().offset) {
160 std::swap(sync, tail.front().sync);
161 tail.pop_front();
162 }
163
164 if (sync.handle != 0) {
165 glClientWaitSync(sync.handle, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
166 sync.Release();
167 }
168
169 if (head.empty() || effective_offset > head.back().offset) {
170 head.emplace_back();
171 head.back().offset = effective_offset;
172 }
173
174 mapped_size = size;
175 return std::make_pair(&mapped_ptr[buffer_pos], static_cast<GLintptr>(buffer_pos));
176}
177
178void StorageBuffer::Unmap() {
179 glFlushMappedBufferRange(gl_target, static_cast<GLintptr>(buffer_pos),
180 static_cast<GLsizeiptr>(mapped_size));
181 buffer_pos += mapped_size;
182}
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.h b/src/video_core/renderer_opengl/gl_stream_buffer.h
new file mode 100644
index 000000000..4bc2f52e0
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.h
@@ -0,0 +1,34 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <memory>
6#include <glad/glad.h>
7#include "common/common_types.h"
8#include "video_core/renderer_opengl/gl_resource_manager.h"
9
10class OGLStreamBuffer : private NonCopyable {
11public:
12 explicit OGLStreamBuffer(GLenum target);
13 virtual ~OGLStreamBuffer() = default;
14
15public:
16 static std::unique_ptr<OGLStreamBuffer> MakeBuffer(bool storage_buffer, GLenum target);
17
18 virtual void Create(size_t size, size_t sync_subdivide) = 0;
19 virtual void Release() {}
20
21 GLuint GetHandle() const;
22
23 virtual std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) = 0;
24 virtual void Unmap() = 0;
25
26protected:
27 OGLBuffer gl_buffer;
28 GLenum gl_target;
29
30 size_t buffer_pos = 0;
31 size_t buffer_size = 0;
32 size_t buffer_sync_subdivide = 0;
33 size_t mapped_size = 0;
34};