diff options
| author | 2018-08-09 21:31:46 +0200 | |
|---|---|---|
| committer | 2018-08-12 15:47:35 +0200 | |
| commit | d7298ec2626f013167ea254276259ac7b39f46be (patch) | |
| tree | c011140a61d25b1f93894b9ed7d683e54b1b8e06 /src | |
| parent | Merge pull request #1029 from bunnei/fix-out-attrib (diff) | |
| download | yuzu-d7298ec2626f013167ea254276259ac7b39f46be.tar.gz yuzu-d7298ec2626f013167ea254276259ac7b39f46be.tar.xz yuzu-d7298ec2626f013167ea254276259ac7b39f46be.zip | |
Update the stream_buffer helper from Citra.
Please see https://github.com/citra-emu/citra/pull/3666 for more details.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 36 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_stream_buffer.cpp | 201 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_stream_buffer.h | 42 |
4 files changed, 98 insertions, 184 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 38a7b1413..94e3f59a7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -36,7 +36,8 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192)); | |||
| 36 | MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); | 36 | MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); |
| 37 | MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); | 37 | MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); |
| 38 | 38 | ||
| 39 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) : emu_window{window} { | 39 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) |
| 40 | : emu_window{window}, stream_buffer(GL_ARRAY_BUFFER, STREAM_BUFFER_SIZE) { | ||
| 40 | // Create sampler objects | 41 | // Create sampler objects |
| 41 | for (size_t i = 0; i < texture_samplers.size(); ++i) { | 42 | for (size_t i = 0; i < texture_samplers.size(); ++i) { |
| 42 | texture_samplers[i].Create(); | 43 | texture_samplers[i].Create(); |
| @@ -57,9 +58,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) : emu_wind | |||
| 57 | const std::string_view extension{ | 58 | const std::string_view extension{ |
| 58 | reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))}; | 59 | reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))}; |
| 59 | 60 | ||
| 60 | if (extension == "GL_ARB_buffer_storage") { | 61 | if (extension == "GL_ARB_direct_state_access") { |
| 61 | has_ARB_buffer_storage = true; | ||
| 62 | } else if (extension == "GL_ARB_direct_state_access") { | ||
| 63 | has_ARB_direct_state_access = true; | 62 | has_ARB_direct_state_access = true; |
| 64 | } else if (extension == "GL_ARB_separate_shader_objects") { | 63 | } else if (extension == "GL_ARB_separate_shader_objects") { |
| 65 | has_ARB_separate_shader_objects = true; | 64 | has_ARB_separate_shader_objects = true; |
| @@ -86,16 +85,14 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) : emu_wind | |||
| 86 | 85 | ||
| 87 | hw_vao.Create(); | 86 | hw_vao.Create(); |
| 88 | 87 | ||
| 89 | stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER); | 88 | state.draw.vertex_buffer = stream_buffer.GetHandle(); |
| 90 | stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2); | ||
| 91 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | ||
| 92 | 89 | ||
| 93 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); | 90 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |
| 94 | state.draw.shader_program = 0; | 91 | state.draw.shader_program = 0; |
| 95 | state.draw.vertex_array = hw_vao.handle; | 92 | state.draw.vertex_array = hw_vao.handle; |
| 96 | state.Apply(); | 93 | state.Apply(); |
| 97 | 94 | ||
| 98 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer->GetHandle()); | 95 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer.GetHandle()); |
| 99 | 96 | ||
| 100 | for (unsigned index = 0; index < uniform_buffers.size(); ++index) { | 97 | for (unsigned index = 0; index < uniform_buffers.size(); ++index) { |
| 101 | auto& buffer = uniform_buffers[index]; | 98 | auto& buffer = uniform_buffers[index]; |
| @@ -111,13 +108,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) : emu_wind | |||
| 111 | LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); | 108 | LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); |
| 112 | } | 109 | } |
| 113 | 110 | ||
| 114 | RasterizerOpenGL::~RasterizerOpenGL() { | 111 | RasterizerOpenGL::~RasterizerOpenGL() {} |
| 115 | if (stream_buffer != nullptr) { | ||
| 116 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | ||
| 117 | state.Apply(); | ||
| 118 | stream_buffer->Release(); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | 112 | ||
| 122 | std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, | 113 | std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, |
| 123 | GLintptr buffer_offset) { | 114 | GLintptr buffer_offset) { |
| @@ -126,7 +117,7 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, | |||
| 126 | const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager; | 117 | const auto& memory_manager = Core::System::GetInstance().GPU().memory_manager; |
| 127 | 118 | ||
| 128 | state.draw.vertex_array = hw_vao.handle; | 119 | state.draw.vertex_array = hw_vao.handle; |
| 129 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | 120 | state.draw.vertex_buffer = stream_buffer.GetHandle(); |
| 130 | state.Apply(); | 121 | state.Apply(); |
| 131 | 122 | ||
| 132 | // Upload all guest vertex arrays sequentially to our buffer | 123 | // Upload all guest vertex arrays sequentially to our buffer |
| @@ -145,7 +136,7 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, | |||
| 145 | Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size); | 136 | Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size); |
| 146 | 137 | ||
| 147 | // Bind the vertex array to the buffer at the current offset. | 138 | // Bind the vertex array to the buffer at the current offset. |
| 148 | glBindVertexBuffer(index, stream_buffer->GetHandle(), buffer_offset, vertex_array.stride); | 139 | glBindVertexBuffer(index, stream_buffer.GetHandle(), buffer_offset, vertex_array.stride); |
| 149 | 140 | ||
| 150 | ASSERT_MSG(vertex_array.divisor == 0, "Vertex buffer divisor unimplemented"); | 141 | ASSERT_MSG(vertex_array.divisor == 0, "Vertex buffer divisor unimplemented"); |
| 151 | 142 | ||
| @@ -205,7 +196,7 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | |||
| 205 | // Helper function for uploading uniform data | 196 | // Helper function for uploading uniform data |
| 206 | const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) { | 197 | const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) { |
| 207 | if (has_ARB_direct_state_access) { | 198 | if (has_ARB_direct_state_access) { |
| 208 | glCopyNamedBufferSubData(stream_buffer->GetHandle(), handle, offset, 0, size); | 199 | glCopyNamedBufferSubData(stream_buffer.GetHandle(), handle, offset, 0, size); |
| 209 | } else { | 200 | } else { |
| 210 | glBindBuffer(GL_COPY_WRITE_BUFFER, handle); | 201 | glBindBuffer(GL_COPY_WRITE_BUFFER, handle); |
| 211 | glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size); | 202 | glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, offset, 0, size); |
| @@ -456,7 +447,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 456 | const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()}; | 447 | const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()}; |
| 457 | const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count}; | 448 | const unsigned vertex_num{is_indexed ? regs.index_array.count : regs.vertex_buffer.count}; |
| 458 | 449 | ||
| 459 | state.draw.vertex_buffer = stream_buffer->GetHandle(); | 450 | state.draw.vertex_buffer = stream_buffer.GetHandle(); |
| 460 | state.Apply(); | 451 | state.Apply(); |
| 461 | 452 | ||
| 462 | size_t buffer_size = CalculateVertexArraysSize(); | 453 | size_t buffer_size = CalculateVertexArraysSize(); |
| @@ -471,8 +462,8 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 471 | 462 | ||
| 472 | u8* buffer_ptr; | 463 | u8* buffer_ptr; |
| 473 | GLintptr buffer_offset; | 464 | GLintptr buffer_offset; |
| 474 | std::tie(buffer_ptr, buffer_offset) = | 465 | std::tie(buffer_ptr, buffer_offset, std::ignore) = |
| 475 | stream_buffer->Map(static_cast<GLsizeiptr>(buffer_size), 4); | 466 | stream_buffer.Map(static_cast<GLsizeiptr>(buffer_size), 4); |
| 476 | 467 | ||
| 477 | u8* offseted_buffer; | 468 | u8* offseted_buffer; |
| 478 | std::tie(offseted_buffer, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset); | 469 | std::tie(offseted_buffer, buffer_offset) = SetupVertexArrays(buffer_ptr, buffer_offset); |
| @@ -500,7 +491,8 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 500 | 491 | ||
| 501 | SetupShaders(offseted_buffer, buffer_offset); | 492 | SetupShaders(offseted_buffer, buffer_offset); |
| 502 | 493 | ||
| 503 | stream_buffer->Unmap(); | 494 | // TODO: Don't use buffer_size here, use the updated buffer_offset. |
| 495 | stream_buffer.Unmap(buffer_size); | ||
| 504 | 496 | ||
| 505 | shader_program_manager->ApplyTo(state); | 497 | shader_program_manager->ApplyTo(state); |
| 506 | state.Apply(); | 498 | state.Apply(); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index bd01dc0ae..19146777c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -139,7 +139,6 @@ private: | |||
| 139 | /// Syncs the blend state to match the guest state | 139 | /// Syncs the blend state to match the guest state |
| 140 | void SyncBlendState(); | 140 | void SyncBlendState(); |
| 141 | 141 | ||
| 142 | bool has_ARB_buffer_storage = false; | ||
| 143 | bool has_ARB_direct_state_access = false; | 142 | bool has_ARB_direct_state_access = false; |
| 144 | bool has_ARB_separate_shader_objects = false; | 143 | bool has_ARB_separate_shader_objects = false; |
| 145 | bool has_ARB_vertex_attrib_binding = false; | 144 | bool has_ARB_vertex_attrib_binding = false; |
| @@ -160,7 +159,7 @@ private: | |||
| 160 | ssbos; | 159 | ssbos; |
| 161 | 160 | ||
| 162 | static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; | 161 | static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; |
| 163 | std::unique_ptr<OGLStreamBuffer> stream_buffer; | 162 | OGLStreamBuffer stream_buffer; |
| 164 | OGLBuffer uniform_buffer; | 163 | OGLBuffer uniform_buffer; |
| 165 | OGLFramebuffer framebuffer; | 164 | OGLFramebuffer framebuffer; |
| 166 | 165 | ||
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp index a2713e9f0..03a8ed8b7 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp +++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp | |||
| @@ -9,174 +9,91 @@ | |||
| 9 | #include "video_core/renderer_opengl/gl_state.h" | 9 | #include "video_core/renderer_opengl/gl_state.h" |
| 10 | #include "video_core/renderer_opengl/gl_stream_buffer.h" | 10 | #include "video_core/renderer_opengl/gl_stream_buffer.h" |
| 11 | 11 | ||
| 12 | class OrphanBuffer : public OGLStreamBuffer { | 12 | OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent) |
| 13 | public: | 13 | : gl_target(target), buffer_size(size) { |
| 14 | explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {} | 14 | gl_buffer.Create(); |
| 15 | ~OrphanBuffer() override; | 15 | glBindBuffer(gl_target, gl_buffer.handle); |
| 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 | 16 | ||
| 57 | std::unique_ptr<OGLStreamBuffer> OGLStreamBuffer::MakeBuffer(bool storage_buffer, GLenum target) { | 17 | GLsizeiptr allocate_size = size; |
| 58 | if (storage_buffer) { | 18 | if (target == GL_ARRAY_BUFFER) { |
| 59 | return std::make_unique<StorageBuffer>(target); | 19 | // On AMD GPU there is a strange crash in indexed drawing. The crash happens when the buffer |
| 20 | // read position is near the end and is an out-of-bound access to the vertex buffer. This is | ||
| 21 | // probably a bug in the driver and is related to the usage of vec3<byte> attributes in the | ||
| 22 | // vertex array. Doubling the allocation size for the vertex buffer seems to avoid the | ||
| 23 | // crash. | ||
| 24 | allocate_size *= 2; | ||
| 60 | } | 25 | } |
| 61 | return std::make_unique<OrphanBuffer>(target); | ||
| 62 | } | ||
| 63 | 26 | ||
| 64 | OrphanBuffer::~OrphanBuffer() { | 27 | if (GLAD_GL_ARB_buffer_storage) { |
| 65 | Release(); | 28 | persistent = true; |
| 29 | coherent = prefer_coherent; | ||
| 30 | GLbitfield flags = | ||
| 31 | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0); | ||
| 32 | glBufferStorage(gl_target, allocate_size, nullptr, flags); | ||
| 33 | mapped_ptr = static_cast<u8*>(glMapBufferRange( | ||
| 34 | gl_target, 0, buffer_size, flags | (coherent ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT))); | ||
| 35 | } else { | ||
| 36 | glBufferData(gl_target, allocate_size, nullptr, GL_STREAM_DRAW); | ||
| 37 | } | ||
| 66 | } | 38 | } |
| 67 | 39 | ||
| 68 | void OrphanBuffer::Create(size_t size, size_t /*sync_subdivide*/) { | 40 | OGLStreamBuffer::~OGLStreamBuffer() { |
| 69 | buffer_pos = 0; | 41 | if (persistent) { |
| 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); | 42 | glBindBuffer(gl_target, gl_buffer.handle); |
| 43 | glUnmapBuffer(gl_target); | ||
| 76 | } | 44 | } |
| 77 | |||
| 78 | glBufferData(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, GL_STREAM_DRAW); | ||
| 79 | } | ||
| 80 | |||
| 81 | void OrphanBuffer::Release() { | ||
| 82 | gl_buffer.Release(); | 45 | gl_buffer.Release(); |
| 83 | } | 46 | } |
| 84 | 47 | ||
| 85 | std::pair<u8*, GLintptr> OrphanBuffer::Map(size_t size, size_t alignment) { | 48 | GLuint OGLStreamBuffer::GetHandle() const { |
| 86 | buffer_pos = Common::AlignUp(buffer_pos, alignment); | 49 | return gl_buffer.handle; |
| 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 | } | 50 | } |
| 105 | 51 | ||
| 106 | void StorageBuffer::Create(size_t size, size_t sync_subdivide) { | 52 | GLsizeiptr OGLStreamBuffer::GetSize() const { |
| 107 | if (gl_buffer.handle != 0) | 53 | return buffer_size; |
| 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 | } | 54 | } |
| 123 | 55 | ||
| 124 | void StorageBuffer::Release() { | 56 | std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr alignment) { |
| 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); | 57 | ASSERT(size <= buffer_size); |
| 58 | ASSERT(alignment <= buffer_size); | ||
| 59 | mapped_size = size; | ||
| 137 | 60 | ||
| 138 | OGLSync sync; | 61 | if (alignment > 0) { |
| 139 | 62 | buffer_pos = Common::AlignUp<size_t>(buffer_pos, alignment); | |
| 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 | } | 63 | } |
| 148 | 64 | ||
| 65 | bool invalidate = false; | ||
| 149 | if (buffer_pos + size > buffer_size) { | 66 | 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; | 67 | buffer_pos = 0; |
| 156 | effective_offset = 0; | 68 | invalidate = true; |
| 157 | } | ||
| 158 | 69 | ||
| 159 | while (!tail.empty() && buffer_pos + size > tail.front().offset) { | 70 | if (persistent) { |
| 160 | std::swap(sync, tail.front().sync); | 71 | glUnmapBuffer(gl_target); |
| 161 | tail.pop_front(); | 72 | } |
| 162 | } | 73 | } |
| 163 | 74 | ||
| 164 | if (sync.handle != 0) { | 75 | if (invalidate | !persistent) { |
| 165 | glClientWaitSync(sync.handle, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); | 76 | GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) | |
| 166 | sync.Release(); | 77 | (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) | |
| 78 | (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT); | ||
| 79 | mapped_ptr = static_cast<u8*>( | ||
| 80 | glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags)); | ||
| 81 | mapped_offset = buffer_pos; | ||
| 167 | } | 82 | } |
| 168 | 83 | ||
| 169 | if (head.empty() || effective_offset > head.back().offset) { | 84 | return std::make_tuple(mapped_ptr + buffer_pos - mapped_offset, buffer_pos, invalidate); |
| 170 | head.emplace_back(); | 85 | } |
| 171 | head.back().offset = effective_offset; | 86 | |
| 87 | void OGLStreamBuffer::Unmap(GLsizeiptr size) { | ||
| 88 | ASSERT(size <= mapped_size); | ||
| 89 | |||
| 90 | if (!coherent && size > 0) { | ||
| 91 | glFlushMappedBufferRange(gl_target, buffer_pos - mapped_offset, size); | ||
| 172 | } | 92 | } |
| 173 | 93 | ||
| 174 | mapped_size = size; | 94 | if (!persistent) { |
| 175 | return std::make_pair(&mapped_ptr[buffer_pos], static_cast<GLintptr>(buffer_pos)); | 95 | glUnmapBuffer(gl_target); |
| 176 | } | 96 | } |
| 177 | 97 | ||
| 178 | void StorageBuffer::Unmap() { | 98 | buffer_pos += size; |
| 179 | glFlushMappedBufferRange(gl_target, static_cast<GLintptr>(buffer_pos), | ||
| 180 | static_cast<GLsizeiptr>(mapped_size)); | ||
| 181 | buffer_pos += mapped_size; | ||
| 182 | } | 99 | } |
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.h b/src/video_core/renderer_opengl/gl_stream_buffer.h index e78dc5784..45592daaf 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.h +++ b/src/video_core/renderer_opengl/gl_stream_buffer.h | |||
| @@ -2,35 +2,41 @@ | |||
| 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 | #pragma once | 5 | #include <tuple> |
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <glad/glad.h> | 6 | #include <glad/glad.h> |
| 9 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 10 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 8 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 11 | 9 | ||
| 12 | class OGLStreamBuffer : private NonCopyable { | 10 | class OGLStreamBuffer : private NonCopyable { |
| 13 | public: | 11 | public: |
| 14 | explicit OGLStreamBuffer(GLenum target); | 12 | explicit OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent = false); |
| 15 | virtual ~OGLStreamBuffer() = default; | 13 | ~OGLStreamBuffer(); |
| 16 | |||
| 17 | public: | ||
| 18 | static std::unique_ptr<OGLStreamBuffer> MakeBuffer(bool storage_buffer, GLenum target); | ||
| 19 | |||
| 20 | virtual void Create(size_t size, size_t sync_subdivide) = 0; | ||
| 21 | virtual void Release() {} | ||
| 22 | 14 | ||
| 23 | GLuint GetHandle() const; | 15 | GLuint GetHandle() const; |
| 16 | GLsizeiptr GetSize() const; | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Allocates a linear chunk of memory in the GPU buffer with at least "size" bytes | ||
| 20 | * and the optional alignment requirement. | ||
| 21 | * If the buffer is full, the whole buffer is reallocated which invalidates old chunks. | ||
| 22 | * The return values are the pointer to the new chunk, the offset within the buffer, | ||
| 23 | * and the invalidation flag for previous chunks. | ||
| 24 | * The actual used size must be specified on unmapping the chunk. | ||
| 25 | */ | ||
| 26 | std::tuple<u8*, GLintptr, bool> Map(GLsizeiptr size, GLintptr alignment = 0); | ||
| 24 | 27 | ||
| 25 | virtual std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) = 0; | 28 | void Unmap(GLsizeiptr size); |
| 26 | virtual void Unmap() = 0; | ||
| 27 | 29 | ||
| 28 | protected: | 30 | private: |
| 29 | OGLBuffer gl_buffer; | 31 | OGLBuffer gl_buffer; |
| 30 | GLenum gl_target; | 32 | GLenum gl_target; |
| 31 | 33 | ||
| 32 | size_t buffer_pos = 0; | 34 | bool coherent = false; |
| 33 | size_t buffer_size = 0; | 35 | bool persistent = false; |
| 34 | size_t buffer_sync_subdivide = 0; | 36 | |
| 35 | size_t mapped_size = 0; | 37 | GLintptr buffer_pos = 0; |
| 38 | GLsizeiptr buffer_size = 0; | ||
| 39 | GLintptr mapped_offset = 0; | ||
| 40 | GLsizeiptr mapped_size = 0; | ||
| 41 | u8* mapped_ptr = nullptr; | ||
| 36 | }; | 42 | }; |