Optimized hardware buffers
Former-commit-id: 59f96166fb259137b5e0445eb5faa0b912b0f29c
This commit is contained in:
parent
c45e22ff7d
commit
70e57a338f
|
|
@ -11,53 +11,6 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <Nazara/Renderer/Debug.hpp>
|
#include <Nazara/Renderer/Debug.hpp>
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
using LockRoutine = nzUInt8* (*)(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size);
|
|
||||||
|
|
||||||
nzUInt8* LockBuffer(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
|
||||||
{
|
|
||||||
NazaraUnused(size);
|
|
||||||
|
|
||||||
if (access == nzBufferAccess_DiscardAndWrite)
|
|
||||||
{
|
|
||||||
GLint bufSize;
|
|
||||||
glGetBufferParameteriv(NzOpenGL::BufferTargetBinding[type], GL_BUFFER_SIZE, &bufSize);
|
|
||||||
|
|
||||||
GLint bufUsage;
|
|
||||||
glGetBufferParameteriv(NzOpenGL::BufferTargetBinding[type], GL_BUFFER_USAGE, &bufUsage);
|
|
||||||
|
|
||||||
// On discard le buffer
|
|
||||||
glBufferData(NzOpenGL::BufferTargetBinding[type], bufSize, nullptr, bufUsage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* ptr = glMapBuffer(NzOpenGL::BufferTarget[type], NzOpenGL::BufferLock[access]);
|
|
||||||
if (ptr)
|
|
||||||
return reinterpret_cast<nzUInt8*>(ptr) + offset;
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nzUInt8* LockBufferRange(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<nzUInt8*>(glMapBufferRange(NzOpenGL::BufferTarget[type], offset, size, NzOpenGL::BufferLockRange[access]));
|
|
||||||
}
|
|
||||||
|
|
||||||
nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size);
|
|
||||||
|
|
||||||
LockRoutine mapBuffer = LockBufferFirstRun;
|
|
||||||
|
|
||||||
nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
|
||||||
{
|
|
||||||
if (glMapBufferRange)
|
|
||||||
mapBuffer = LockBufferRange;
|
|
||||||
else
|
|
||||||
mapBuffer = LockBuffer;
|
|
||||||
|
|
||||||
return mapBuffer(type, access, offset, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NzHardwareBuffer::NzHardwareBuffer(NzBuffer* parent, nzBufferType type) :
|
NzHardwareBuffer::NzHardwareBuffer(NzBuffer* parent, nzBufferType type) :
|
||||||
m_type(type),
|
m_type(type),
|
||||||
m_parent(parent)
|
m_parent(parent)
|
||||||
|
|
@ -98,17 +51,19 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int
|
||||||
|
|
||||||
NzOpenGL::BindBuffer(m_type, m_buffer);
|
NzOpenGL::BindBuffer(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/Buffer_Object_Streaming
|
||||||
|
if (forceDiscard)
|
||||||
|
glBufferData(NzOpenGL::BufferTarget[m_type], totalSize, 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, (forceDiscard) ? nzBufferAccess_DiscardAndWrite : nzBufferAccess_WriteOnly, offset, size);
|
void* ptr = Map((forceDiscard) ? nzBufferAccess_DiscardAndWrite : nzBufferAccess_WriteOnly, offset, size);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
NazaraError("Failed to map buffer");
|
NazaraError("Failed to map buffer");
|
||||||
|
|
@ -117,15 +72,7 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int
|
||||||
|
|
||||||
std::memcpy(ptr, data, size);
|
std::memcpy(ptr, data, size);
|
||||||
|
|
||||||
if (glUnmapBuffer(NzOpenGL::BufferTarget[m_type]) != GL_TRUE)
|
Unmap();
|
||||||
{
|
|
||||||
// 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) + ')');
|
|
||||||
|
|
||||||
glBufferData(NzOpenGL::BufferTarget[m_type], totalSize, nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -142,10 +89,20 @@ void* NzHardwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned
|
||||||
|
|
||||||
NzOpenGL::BindBuffer(m_type, m_buffer);
|
NzOpenGL::BindBuffer(m_type, m_buffer);
|
||||||
|
|
||||||
if (access == nzBufferAccess_DiscardAndWrite)
|
if (glMapBufferRange)
|
||||||
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
|
return glMapBufferRange(NzOpenGL::BufferTarget[m_type], offset, size, NzOpenGL::BufferLockRange[access]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// http://www.opengl.org/wiki/Buffer_Object_Streaming
|
||||||
|
if (access == nzBufferAccess_DiscardAndWrite)
|
||||||
|
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
|
||||||
|
|
||||||
return mapBuffer(m_type, access, offset, size);
|
nzUInt8* ptr = static_cast<nzUInt8*>(glMapBuffer(NzOpenGL::BufferTarget[m_type], NzOpenGL::BufferLock[access]));
|
||||||
|
if (ptr)
|
||||||
|
ptr += offset;
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NzHardwareBuffer::Unmap()
|
bool NzHardwareBuffer::Unmap()
|
||||||
|
|
|
||||||
|
|
@ -1863,10 +1863,11 @@ static_assert(sizeof(NzOpenGL::BufferLock)/sizeof(GLenum) == nzBufferAccess_Max+
|
||||||
|
|
||||||
GLenum NzOpenGL::BufferLockRange[] =
|
GLenum NzOpenGL::BufferLockRange[] =
|
||||||
{
|
{
|
||||||
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_DiscardAndWrite
|
// http://www.opengl.org/discussion_boards/showthread.php/170118-VBOs-strangely-slow?p=1198118#post1198118
|
||||||
GL_MAP_READ_BIT, // nzBufferAccess_ReadOnly
|
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_DiscardAndWrite
|
||||||
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_ReadWrite
|
GL_MAP_READ_BIT, // nzBufferAccess_ReadOnly
|
||||||
GL_MAP_WRITE_BIT // nzBufferAccess_WriteOnly
|
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_ReadWrite
|
||||||
|
GL_MAP_WRITE_BIT // nzBufferAccess_WriteOnly
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(NzOpenGL::BufferLockRange)/sizeof(GLenum) == nzBufferAccess_Max+1, "Buffer lock range array is incomplete");
|
static_assert(sizeof(NzOpenGL::BufferLockRange)/sizeof(GLenum) == nzBufferAccess_Max+1, "Buffer lock range array is incomplete");
|
||||||
|
|
@ -1889,11 +1890,10 @@ static_assert(sizeof(NzOpenGL::BufferTargetBinding)/sizeof(GLenum) == nzBufferTy
|
||||||
|
|
||||||
GLenum NzOpenGL::BufferUsage[] =
|
GLenum NzOpenGL::BufferUsage[] =
|
||||||
{
|
{
|
||||||
// J'ai choisi DYNAMIC à la place de STREAM car DYNAMIC semble plus adapté au profil "une mise à jour pour quelques rendus"
|
// D'après la documentation, GL_STREAM_DRAW semble être plus adapté à notre cas (ratio modification/rendu 1:2-3)
|
||||||
// Ce qui est je pense le scénario qui arrivera le plus souvent (Prévoir une option pour permettre d'utiliser le STREAM_DRAW ?)
|
// Source: http://www.opengl.org/sdk/docs/man/html/glBufferData.xhtml
|
||||||
// Source: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=160839
|
GL_STREAM_DRAW, // nzBufferUsage_Dynamic
|
||||||
GL_DYNAMIC_DRAW, // nzBufferUsage_Dynamic
|
GL_STATIC_DRAW // nzBufferUsage_Static
|
||||||
GL_STATIC_DRAW // nzBufferUsage_Static
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(NzOpenGL::BufferUsage)/sizeof(GLenum) == nzBufferUsage_Max+1, "Buffer usage array is incomplete");
|
static_assert(sizeof(NzOpenGL::BufferUsage)/sizeof(GLenum) == nzBufferUsage_Max+1, "Buffer usage array is incomplete");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue