diff options
| author | 2018-03-19 17:10:59 -0400 | |
|---|---|---|
| committer | 2018-03-19 23:14:02 -0400 | |
| commit | 0e4b9cdde408871f542a2a3093963ebbaa007d33 (patch) | |
| tree | c183a90182c5a0ba32b5787bdbc1dfc35a4f6ffb | |
| parent | externals: Update Glad to latest version used by Citra. (diff) | |
| download | yuzu-0e4b9cdde408871f542a2a3093963ebbaa007d33.tar.gz yuzu-0e4b9cdde408871f542a2a3093963ebbaa007d33.tar.xz yuzu-0e4b9cdde408871f542a2a3093963ebbaa007d33.zip | |
renderer_gl: Port over gl_stream_buffer module from Citra.
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_stream_buffer.cpp | 182 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_stream_buffer.h | 34 |
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 | |||
| 12 | class OrphanBuffer : public OGLStreamBuffer { | ||
| 13 | public: | ||
| 14 | explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {} | ||
| 15 | ~OrphanBuffer() override; | ||
| 16 | |||
| 17 | private: | ||
| 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 | |||
| 27 | class StorageBuffer : public OGLStreamBuffer { | ||
| 28 | public: | ||
| 29 | explicit StorageBuffer(GLenum target) : OGLStreamBuffer(target) {} | ||
| 30 | ~StorageBuffer() override; | ||
| 31 | |||
| 32 | private: | ||
| 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 | |||
| 49 | OGLStreamBuffer::OGLStreamBuffer(GLenum target) { | ||
| 50 | gl_target = target; | ||
| 51 | } | ||
| 52 | |||
| 53 | GLuint OGLStreamBuffer::GetHandle() const { | ||
| 54 | return gl_buffer.handle; | ||
| 55 | } | ||
| 56 | |||
| 57 | std::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 | |||
| 64 | OrphanBuffer::~OrphanBuffer() { | ||
| 65 | Release(); | ||
| 66 | } | ||
| 67 | |||
| 68 | void 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 | |||
| 81 | void OrphanBuffer::Release() { | ||
| 82 | gl_buffer.Release(); | ||
| 83 | } | ||
| 84 | |||
| 85 | std::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 | |||
| 96 | void 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 | |||
| 102 | StorageBuffer::~StorageBuffer() { | ||
| 103 | Release(); | ||
| 104 | } | ||
| 105 | |||
| 106 | void 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 | |||
| 124 | void 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 | |||
| 135 | std::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 | |||
| 178 | void 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 | |||
| 10 | class OGLStreamBuffer : private NonCopyable { | ||
| 11 | public: | ||
| 12 | explicit OGLStreamBuffer(GLenum target); | ||
| 13 | virtual ~OGLStreamBuffer() = default; | ||
| 14 | |||
| 15 | public: | ||
| 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 | |||
| 26 | protected: | ||
| 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 | }; | ||