X-Git-Url: https://git.ucc.asn.au/?p=ipdf%2Fcode.git;a=blobdiff_plain;f=src%2Fgraphicsbuffer.cpp;h=217fa9a00129e859eb9b5bc16d6d02ea8a686ab9;hp=43143d63e8a03d1a8a84b84dfaca4590d973c08b;hb=e35bf651e7ebfe4932e877780bb00397c41a7ec2;hpb=f5263ffb797938b07eec50ea1e7fb54a2a8d47c7 diff --git a/src/graphicsbuffer.cpp b/src/graphicsbuffer.cpp index 43143d6..217fa9a 100644 --- a/src/graphicsbuffer.cpp +++ b/src/graphicsbuffer.cpp @@ -1,7 +1,5 @@ #include "graphicsbuffer.h" -#define GL_GLEXT_PROTOTYPES -#include -#include +#include "log.h" using namespace IPDF; @@ -38,7 +36,7 @@ static GLenum BufferUsageToGLUsage(GraphicsBuffer::BufferUsage buffer_usage) usage = GL_STREAM_COPY; break; default: - SDL_assert(false && "Unknown buffer usage type."); + SDL_assert(false && "Unknown buffer usage type."); //WTF? usage = GL_DYNAMIC_DRAW; } return usage; @@ -58,6 +56,8 @@ static GLenum BufferTypeToGLType(GraphicsBuffer::BufferType buffer_type) return GL_PIXEL_UNPACK_BUFFER; case GraphicsBuffer::BufferTypeUniform: return GL_UNIFORM_BUFFER; + case GraphicsBuffer::BufferTypeTexture: + return GL_TEXTURE_BUFFER; case GraphicsBuffer::BufferTypeDrawIndirect: return GL_DRAW_INDIRECT_BUFFER; default: @@ -67,6 +67,14 @@ static GLenum BufferTypeToGLType(GraphicsBuffer::BufferType buffer_type) GraphicsBuffer::GraphicsBuffer() { + m_invalidated = true; + m_map_pointer = NULL; + m_buffer_size = 0; + m_buffer_shape_dirty = true; + m_buffer_handle = 0; + m_buffer_usage = BufferUsageDynamicDraw; + m_faking_map = false; + m_name = "Unnamed Buffer"; SetUsage(BufferUsageStaticDraw); } @@ -81,13 +89,53 @@ GraphicsBuffer::~GraphicsBuffer() void GraphicsBuffer::SetType(GraphicsBuffer::BufferType bufType) { - glGenBuffers(1, &m_buffer_handle); m_buffer_type = bufType; } +void GraphicsBuffer::SetName(const char *name) +{ + m_name = name; +} + void GraphicsBuffer::SetUsage(GraphicsBuffer::BufferUsage bufUsage) { - m_buffer_usage = bufUsage; + if (bufUsage != m_buffer_usage) + { + m_buffer_usage = bufUsage; + m_buffer_shape_dirty = true; + } +} + +void GraphicsBuffer::Invalidate() +{ + m_invalidated = true; + if (!m_buffer_shape_dirty) + { + // Orphan the block of memory we're pointing to. + Upload(m_buffer_size, NULL); + } + // Apparently not supported. + //glInvalidateBufferData(m_buffer_handle); +} + +bool GraphicsBuffer::RecreateBuffer(const void *data) +{ + // If the buffer is not dirty, don't recreate it. + if (!m_buffer_shape_dirty) return false; + // If the buffer is mapped, don't recreate it. + if (!m_faking_map && m_map_pointer) return false; + // If the buffer has data in it we need, don't recreate it. + if (!m_invalidated) return false; + if (m_buffer_handle) + { + glDeleteBuffers(1, &m_buffer_handle); + } + glGenBuffers(1, &m_buffer_handle); + glObjectLabel(GL_BUFFER, m_buffer_handle, -1, m_name); + m_buffer_shape_dirty = false; + if (m_buffer_size) + Upload(m_buffer_size, data); + return true; } void* GraphicsBuffer::Map(bool read, bool write, bool invalidate) @@ -95,34 +143,74 @@ void* GraphicsBuffer::Map(bool read, bool write, bool invalidate) GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_BUFFER_BIT:0); GLenum target = BufferTypeToGLType(m_buffer_type); + if (invalidate) + { + m_invalidated = true; + + // Intel's Mesa driver does not rename the buffer when we map with GL_MAP_INVALIDATE_BUFFER_BIT, + // resulting in the CPU stalling waiting for rendering from the buffer to complete on the GPU. + // We manually force the buffer to be renamed here to avoid this. + m_buffer_shape_dirty = true; + } + + if (m_map_pointer) + Warn("Tried to map already mapped buffer!"); + + + if (!read && m_buffer_usage == BufferUsage::BufferUsageStaticDraw) + { + m_map_pointer = malloc(m_buffer_size); + m_faking_map = true; + return m_map_pointer; + } + + RecreateBuffer(); + Bind(); - return glMapBufferRange(target, 0, m_buffer_size, access); + m_map_pointer = glMapBufferRange(target, 0, m_buffer_size, access); - //TODO: Emulate DSA - //return glMapNamedBufferEXT(m_bufferHandle, access); + return m_map_pointer; } void* GraphicsBuffer::MapRange(int offset, int length, bool read, bool write, bool invalidate) { GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_RANGE_BIT:0); GLenum target = BufferTypeToGLType(m_buffer_type); - + + if (m_map_pointer) + Warn("Tried to map already mapped buffer!"); + + RecreateBuffer(); + Bind(); - return glMapBufferRange(target, offset, length, access); - - //TODO: Emulate DSA - //return glMapNamedBufferRangeEXT(m_bufferHandle, offset, length, access); + m_map_pointer = glMapBufferRange(target, offset, length, access); + return m_map_pointer; } void GraphicsBuffer::UnMap() { GLenum target = BufferTypeToGLType(m_buffer_type); + // If we're not mapped, unmapping is a no-op. + if (!m_map_pointer) + return; + + if (m_faking_map) + { + Upload(m_buffer_size, m_map_pointer); + free(m_map_pointer); + m_map_pointer = NULL; + m_invalidated = false; + m_faking_map = false; + return; + } + Bind(); glUnmapBuffer(target); - //glUnmapNamedBufferEXT(m_bufferHandle); + m_map_pointer = NULL; + m_invalidated = false; } void GraphicsBuffer::Upload(size_t length, const void* data) @@ -130,44 +218,54 @@ void GraphicsBuffer::Upload(size_t length, const void* data) GLenum target = BufferTypeToGLType(m_buffer_type); GLenum usage = BufferUsageToGLUsage(m_buffer_usage); - - Bind(); - glBufferData(target, length, data, usage); + + m_invalidated = true; m_buffer_size = length; - //glNamedBufferDataEXT(m_bufferHandle, length, data, usage); + if (!RecreateBuffer(data)) + { + Bind(); + glBufferData(target, length, data, usage); + } + if (data != NULL) + m_invalidated = false; } void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* data) { GLenum target = BufferTypeToGLType(m_buffer_type); + + RecreateBuffer(); Bind(); glBufferSubData(target, offset, length, data); - //glNamedBufferSubDataEXT(m_bufferHandle, offset, length, data); + m_invalidated = false; } void GraphicsBuffer::Resize(size_t length) { if (m_invalidated) { - Upload(length, nullptr); + m_buffer_size = length; } else { + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Resizing buffer."); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, NULL, GL_TRUE); // Create a new buffer and copy the old data into it. UnMap(); GLuint old_buffer = m_buffer_handle; glGenBuffers(1, &m_buffer_handle); - Upload(length, nullptr); + Upload(length, NULL); glBindBuffer(GL_COPY_READ_BUFFER, old_buffer); glBindBuffer(GL_COPY_WRITE_BUFFER, m_buffer_handle); glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, m_buffer_size); glDeleteBuffers(1, &old_buffer); + m_buffer_size = length; + glPopDebugGroup(); } - } -void GraphicsBuffer::Bind() +void GraphicsBuffer::Bind() const { if (m_buffer_type == BufferTypeUniform) glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_buffer_handle); @@ -175,3 +273,7 @@ void GraphicsBuffer::Bind() glBindBuffer(BufferTypeToGLType(m_buffer_type), m_buffer_handle); } +void GraphicsBuffer::BindRange(size_t start, size_t size) const +{ + glBindBufferRange(BufferTypeToGLType(m_buffer_type), 0, m_buffer_handle, start, size); +}