gl_stream_buffer.cpp
1 // Copyright 2022 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #include "common/alignment.h" 6 #include "common/assert.h" 7 #include "common/microprofile.h" 8 #include "video_core/renderer_opengl/gl_driver.h" 9 #include "video_core/renderer_opengl/gl_stream_buffer.h" 10 11 MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning", 12 MP_RGB(128, 128, 192)); 13 14 namespace OpenGL { 15 16 OGLStreamBuffer::OGLStreamBuffer(Driver& driver, GLenum target, GLsizeiptr size, 17 bool prefer_coherent) 18 : gl_target(target), buffer_size(size) { 19 gl_buffer.Create(); 20 glBindBuffer(gl_target, gl_buffer.handle); 21 22 GLsizeiptr allocate_size = size; 23 if (driver.HasBug(DriverBug::VertexArrayOutOfBound) && target == GL_ARRAY_BUFFER) { 24 allocate_size *= 2; 25 } 26 27 if (GLAD_GL_ARB_buffer_storage) { 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 } 38 } 39 40 OGLStreamBuffer::~OGLStreamBuffer() { 41 if (persistent) { 42 glBindBuffer(gl_target, gl_buffer.handle); 43 glUnmapBuffer(gl_target); 44 } 45 gl_buffer.Release(); 46 } 47 48 GLuint OGLStreamBuffer::GetHandle() const { 49 return gl_buffer.handle; 50 } 51 52 GLsizeiptr OGLStreamBuffer::GetSize() const { 53 return buffer_size; 54 } 55 56 std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr alignment) { 57 ASSERT_MSG(size <= buffer_size, "Requested size {} exceeds buffer size {}", size, buffer_size); 58 ASSERT(alignment <= buffer_size); 59 mapped_size = size; 60 61 if (alignment > 0) { 62 buffer_pos = Common::AlignUp<std::size_t>(buffer_pos, alignment); 63 } 64 65 bool invalidate = false; 66 if (buffer_pos + size > buffer_size) { 67 buffer_pos = 0; 68 invalidate = true; 69 70 if (persistent) { 71 glUnmapBuffer(gl_target); 72 } 73 } 74 75 if (invalidate || !persistent) { 76 MICROPROFILE_SCOPE(OpenGL_StreamBuffer); 77 GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) | 78 (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) | 79 (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT); 80 mapped_ptr = static_cast<u8*>( 81 glMapBufferRange(gl_target, buffer_pos, buffer_size - buffer_pos, flags)); 82 mapped_offset = buffer_pos; 83 } 84 85 return std::make_tuple(mapped_ptr + buffer_pos - mapped_offset, buffer_pos, invalidate); 86 } 87 88 void OGLStreamBuffer::Unmap(GLsizeiptr size) { 89 ASSERT(size <= mapped_size); 90 91 if (!coherent && size > 0) { 92 glFlushMappedBufferRange(gl_target, buffer_pos - mapped_offset, size); 93 } 94 95 if (!persistent) { 96 glUnmapBuffer(gl_target); 97 } 98 99 buffer_pos += size; 100 } 101 102 } // namespace OpenGL