nVidia's driver does not like you mapping a STATIC buffer, as they're
usually in parts of VRAM not directly accessible by the CPU. The driver
therefore has to migrate the buffer somewhere slower.
We initialize the object bounds buffer by mapping it and writing directly
into it. This is good where we're doing coordinate transform on the CPU:
we're changing it every frame and it can be a dynamic buffer, but we only
need to do it once if the GPU is doing coordinate transforms so we make it a
static buffer.
This change "fakes" mapping a STATIC buffer for the first time by allocating
some CPU-side memory, having the application write into that, and then initializing
the buffer with that. This removes a performance warning on nVidia when switching
to GPU-side coordinate transforms.
m_buffer_shape_dirty = true;
m_buffer_handle = 0;
m_buffer_usage = BufferUsageDynamicDraw;
m_buffer_shape_dirty = true;
m_buffer_handle = 0;
m_buffer_usage = BufferUsageDynamicDraw;
SetUsage(BufferUsageStaticDraw);
}
SetUsage(BufferUsageStaticDraw);
}
//glInvalidateBufferData(m_buffer_handle);
}
//glInvalidateBufferData(m_buffer_handle);
}
-void GraphicsBuffer::RecreateBuffer()
+bool GraphicsBuffer::RecreateBuffer(const void *data)
{
// If the buffer is not dirty, don't recreate it.
{
// If the buffer is not dirty, don't recreate it.
- if (!m_buffer_shape_dirty) return;
+ if (!m_buffer_shape_dirty) return false;
// If the buffer is mapped, don't recreate it.
// If the buffer is mapped, don't recreate it.
- if (m_map_pointer) return;
+ if (!m_faking_map && m_map_pointer) return false;
// If the buffer has data in it we need, don't recreate it.
// If the buffer has data in it we need, don't recreate it.
- if (!m_invalidated) return;
+ if (!m_invalidated) return false;
if (m_buffer_handle)
{
glDeleteBuffers(1, &m_buffer_handle);
if (m_buffer_handle)
{
glDeleteBuffers(1, &m_buffer_handle);
glGenBuffers(1, &m_buffer_handle);
m_buffer_shape_dirty = false;
if (m_buffer_size)
glGenBuffers(1, &m_buffer_handle);
m_buffer_shape_dirty = false;
if (m_buffer_size)
- Upload(m_buffer_size, nullptr);
+ Upload(m_buffer_size, data);
+ return true;
}
void* GraphicsBuffer::Map(bool read, bool write, bool invalidate)
}
void* GraphicsBuffer::Map(bool read, bool write, bool invalidate)
if (m_map_pointer)
Warn("Tried to map already mapped buffer!");
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();
RecreateBuffer();
Bind();
void GraphicsBuffer::UnMap()
{
GLenum target = BufferTypeToGLType(m_buffer_type);
void GraphicsBuffer::UnMap()
{
GLenum target = BufferTypeToGLType(m_buffer_type);
+
+ if (m_faking_map)
+ {
+ Upload(m_buffer_size, m_map_pointer);
+ free(m_map_pointer);
+ m_map_pointer = nullptr;
+ m_invalidated = false;
+ m_faking_map = false;
+ return;
+ }
Bind();
glUnmapBuffer(target);
Bind();
glUnmapBuffer(target);
GLenum usage = BufferUsageToGLUsage(m_buffer_usage);
m_invalidated = true;
GLenum usage = BufferUsageToGLUsage(m_buffer_usage);
m_invalidated = true;
- RecreateBuffer();
-
- Bind();
- glBufferData(target, length, data, usage);
+ m_buffer_size = length;
+ if (!RecreateBuffer(data))
+ {
+ Bind();
+ glBufferData(target, length, data, usage);
+ }
if (data != nullptr)
m_invalidated = false;
if (data != nullptr)
m_invalidated = false;
- m_buffer_size = length;
}
void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* data)
}
void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* data)
if (m_invalidated)
{
m_buffer_size = length;
if (m_invalidated)
{
m_buffer_size = length;
void Bind() const;
private:
void Bind() const;
private:
+ bool RecreateBuffer(const void *data = nullptr);
GLuint m_buffer_handle;
BufferType m_buffer_type;
BufferUsage m_buffer_usage;
GLuint m_buffer_handle;
BufferType m_buffer_type;
BufferUsage m_buffer_usage;
size_t m_buffer_size;
bool m_invalidated;
bool m_buffer_shape_dirty;
size_t m_buffer_size;
bool m_invalidated;
bool m_buffer_shape_dirty;