OpenGL 3.1 core profile support.
[ipdf/code.git] / src / graphicsbuffer.cpp
index 43143d6..750fc8b 100644 (file)
@@ -1,7 +1,5 @@
 #include "graphicsbuffer.h"
-#define GL_GLEXT_PROTOTYPES
-#include <SDL_opengl.h>
-#include <GL/glext.h>
+#include "log.h"
 
 using namespace IPDF;
 
@@ -67,6 +65,12 @@ static GLenum BufferTypeToGLType(GraphicsBuffer::BufferType buffer_type)
 
 GraphicsBuffer::GraphicsBuffer()
 {
+       m_invalidated = true;
+       m_map_pointer = nullptr;
+       m_buffer_size = 0;
+       m_buffer_shape_dirty = true;
+       m_buffer_handle = 0;
+       m_buffer_usage = BufferUsageDynamicDraw;
        SetUsage(BufferUsageStaticDraw);
 }
 
@@ -81,13 +85,41 @@ GraphicsBuffer::~GraphicsBuffer()
 
 void GraphicsBuffer::SetType(GraphicsBuffer::BufferType bufType)
 {
-       glGenBuffers(1, &m_buffer_handle);
        m_buffer_type = bufType;
 }
 
 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;
+       // Apparently not supported.
+       //glInvalidateBufferData(m_buffer_handle);
+}
+
+void GraphicsBuffer::RecreateBuffer()
+{
+       // If the buffer is not dirty, don't recreate it.
+       if (!m_buffer_shape_dirty) return;
+       // If the buffer is mapped, don't recreate it.
+       if (m_map_pointer) return;
+       // If the buffer has data in it we need, don't recreate it.
+       if (!m_invalidated) return;
+       if (m_buffer_handle)
+       {
+               glDeleteBuffers(1, &m_buffer_handle);
+       }
+       glGenBuffers(1, &m_buffer_handle);
+       m_buffer_shape_dirty = false;
+       if (m_buffer_size)
+               Upload(m_buffer_size, nullptr);
 }
 
 void* GraphicsBuffer::Map(bool read, bool write, bool invalidate)
@@ -95,25 +127,42 @@ 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!");    
+
+       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()
@@ -122,7 +171,8 @@ void GraphicsBuffer::UnMap()
        
        Bind();
        glUnmapBuffer(target);
-       //glUnmapNamedBufferEXT(m_bufferHandle);
+       m_map_pointer = nullptr;
+       m_invalidated = false;
 }
 
 void GraphicsBuffer::Upload(size_t length, const void* data)
@@ -130,27 +180,34 @@ void GraphicsBuffer::Upload(size_t length, const void* data)
        GLenum target = BufferTypeToGLType(m_buffer_type);
        
        GLenum usage = BufferUsageToGLUsage(m_buffer_usage);
+
+       m_invalidated = true;
+       RecreateBuffer();
        
        Bind();
        glBufferData(target, length, data, usage);
+       if (data != nullptr)
+               m_invalidated = false;
        m_buffer_size = length;
-       //glNamedBufferDataEXT(m_bufferHandle, length, data, usage);
 }
 
 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;
+               RecreateBuffer();       
        }
        else
        {
@@ -163,11 +220,11 @@ void GraphicsBuffer::Resize(size_t length)
                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;
        }
-
 }
 
-void GraphicsBuffer::Bind()
+void GraphicsBuffer::Bind() const
 {
        if (m_buffer_type == BufferTypeUniform)
                glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_buffer_handle);

UCC git Repository :: git.ucc.asn.au