Optimized Buffer locking/filling

Former-commit-id: 41cb66257f3eeef375086bf51f26230a06ca9eb8
This commit is contained in:
Lynix 2013-03-06 22:40:15 +01:00
parent aa67a52e9c
commit 9f780ef2bd
8 changed files with 26 additions and 17 deletions

View File

@ -30,7 +30,7 @@ class NAZARA_API NzBuffer : public NzResource, NzNonCopyable
bool Create(unsigned int length, nzUInt8 typeSize, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); bool Create(unsigned int length, nzUInt8 typeSize, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static);
void Destroy(); void Destroy();
bool Fill(const void* data, unsigned int offset, unsigned int length); bool Fill(const void* data, unsigned int offset, unsigned int length, bool forceDiscard = false);
NzBufferImpl* GetImpl() const; NzBufferImpl* GetImpl() const;
unsigned int GetLength() const; unsigned int GetLength() const;

View File

@ -18,7 +18,7 @@ class NAZARA_API NzBufferImpl
virtual bool Create(unsigned int size, nzBufferUsage usage = nzBufferUsage_Static) = 0; virtual bool Create(unsigned int size, nzBufferUsage usage = nzBufferUsage_Static) = 0;
virtual void Destroy() = 0; virtual void Destroy() = 0;
virtual bool Fill(const void* data, unsigned int offset, unsigned int size) = 0; virtual bool Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard = false) = 0;
virtual void* GetPointer() = 0; virtual void* GetPointer() = 0;

View File

@ -4,6 +4,7 @@
#include <Nazara/Renderer/OpenGL.hpp> #include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/HardwareBuffer.hpp> #include <Nazara/Renderer/HardwareBuffer.hpp>
#include <Nazara/Core/Clock.hpp>
#include <Nazara/Core/Error.hpp> #include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Context.hpp> #include <Nazara/Renderer/Context.hpp>
#include <cstring> #include <cstring>
@ -105,29 +106,32 @@ void NzHardwareBuffer::Destroy()
glDeleteBuffers(1, &m_buffer); glDeleteBuffers(1, &m_buffer);
} }
bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size) bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard)
{ {
NzContext::EnsureContext(); NzContext::EnsureContext();
unsigned int totalSize = m_parent->GetSize();
if (!forceDiscard)
forceDiscard = (size == totalSize);
GLuint previous; GLuint previous;
glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous)); glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
if (previous != m_buffer) if (previous != m_buffer)
glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer); glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
// http://www.opengl.org/wiki/Vertex_Specification_Best_Practices
if (forceDiscard)
glBufferData(NzOpenGL::BufferTarget[m_type], totalSize, nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
// Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil // Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil
// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/ // http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
if (size < 32*1024) if (size < 32*1024)
{
// http://www.opengl.org/wiki/Vertex_Specification_Best_Practices
if (size == m_parent->GetSize())
glBufferData(NzOpenGL::BufferTarget[m_type], size, nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
glBufferSubData(NzOpenGL::BufferTarget[m_type], offset, size, data); glBufferSubData(NzOpenGL::BufferTarget[m_type], offset, size, data);
}
else else
{ {
nzUInt8* ptr = mapBuffer(m_type, (size == m_parent->GetSize()) ? nzBufferAccess_DiscardAndWrite : nzBufferAccess_WriteOnly, offset, size); nzUInt8* ptr = mapBuffer(m_type, (forceDiscard) ? nzBufferAccess_DiscardAndWrite : nzBufferAccess_WriteOnly, offset, size);
if (!ptr) if (!ptr)
{ {
NazaraError("Failed to map buffer"); NazaraError("Failed to map buffer");
@ -141,7 +145,7 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int
// Une erreur rare est survenue, nous devons réinitialiser le buffer // Une erreur rare est survenue, nous devons réinitialiser le buffer
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')'); NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetStorage()]); glBufferData(NzOpenGL::BufferTarget[m_type], totalSize, nullptr, NzOpenGL::BufferUsage[m_parent->GetStorage()]);
return false; return false;
} }
@ -175,6 +179,9 @@ void* NzHardwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned
if (previous != m_buffer) if (previous != m_buffer)
glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer); glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
if (access == nzBufferAccess_DiscardAndWrite)
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
void* ptr = mapBuffer(m_type, access, offset, size); void* ptr = mapBuffer(m_type, access, offset, size);
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées) // Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées)

View File

@ -22,7 +22,7 @@ class NzHardwareBuffer : public NzBufferImpl
bool Create(unsigned int size, nzBufferUsage usage = nzBufferUsage_Static); bool Create(unsigned int size, nzBufferUsage usage = nzBufferUsage_Static);
void Destroy(); void Destroy();
bool Fill(const void* data, unsigned int offset, unsigned int size); bool Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard);
void* GetPointer(); void* GetPointer();

View File

@ -372,7 +372,7 @@ void NzRenderer::FillInstancingBuffer(const NzRenderer::InstancingData* instanci
} }
#endif #endif
if (!s_instancingBuffer->Fill(instancingData, 0, instanceCount)) if (!s_instancingBuffer->Fill(instancingData, 0, instanceCount, true))
NazaraError("Failed to fill instancing buffer"); NazaraError("Failed to fill instancing buffer");
} }

View File

@ -117,7 +117,7 @@ void NzBuffer::Destroy()
} }
} }
bool NzBuffer::Fill(const void* data, unsigned int offset, unsigned int length) bool NzBuffer::Fill(const void* data, unsigned int offset, unsigned int length, bool forceDiscard)
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
@ -133,7 +133,7 @@ bool NzBuffer::Fill(const void* data, unsigned int offset, unsigned int length)
} }
#endif #endif
return m_impl->Fill(data, offset*m_typeSize, ((length == 0) ? m_length-offset : length)*m_typeSize); return m_impl->Fill(data, offset*m_typeSize, ((length == 0) ? m_length-offset : length)*m_typeSize, forceDiscard);
} }
NzBufferImpl* NzBuffer::GetImpl() const NzBufferImpl* NzBuffer::GetImpl() const

View File

@ -44,8 +44,10 @@ void NzSoftwareBuffer::Destroy()
delete[] m_buffer; delete[] m_buffer;
} }
bool NzSoftwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size) bool NzSoftwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard)
{ {
NazaraUnused(forceDiscard);
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (m_mapped) if (m_mapped)
{ {

View File

@ -19,7 +19,7 @@ class NzSoftwareBuffer : public NzBufferImpl
bool Create(unsigned int size, nzBufferUsage usage = nzBufferUsage_Static); bool Create(unsigned int size, nzBufferUsage usage = nzBufferUsage_Static);
void Destroy(); void Destroy();
bool Fill(const void* data, unsigned int offset, unsigned int size); bool Fill(const void* data, unsigned int offset, unsigned int size, bool forceDiscard);
void* GetPointer(); void* GetPointer();