Optimized hardware buffers
Former-commit-id: 59f96166fb259137b5e0445eb5faa0b912b0f29c
This commit is contained in:
parent
c45e22ff7d
commit
70e57a338f
|
|
@ -11,53 +11,6 @@
|
|||
#include <stdexcept>
|
||||
#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) :
|
||||
m_type(type),
|
||||
m_parent(parent)
|
||||
|
|
@ -98,17 +51,19 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int
|
|||
|
||||
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
|
||||
// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
|
||||
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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (glUnmapBuffer(NzOpenGL::BufferTarget[m_type]) != GL_TRUE)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
Unmap();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -142,10 +89,20 @@ void* NzHardwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned
|
|||
|
||||
NzOpenGL::BindBuffer(m_type, m_buffer);
|
||||
|
||||
if (access == nzBufferAccess_DiscardAndWrite)
|
||||
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
|
||||
if (glMapBufferRange)
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -1863,10 +1863,11 @@ static_assert(sizeof(NzOpenGL::BufferLock)/sizeof(GLenum) == nzBufferAccess_Max+
|
|||
|
||||
GLenum NzOpenGL::BufferLockRange[] =
|
||||
{
|
||||
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_DiscardAndWrite
|
||||
GL_MAP_READ_BIT, // nzBufferAccess_ReadOnly
|
||||
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_ReadWrite
|
||||
GL_MAP_WRITE_BIT // nzBufferAccess_WriteOnly
|
||||
// http://www.opengl.org/discussion_boards/showthread.php/170118-VBOs-strangely-slow?p=1198118#post1198118
|
||||
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_DiscardAndWrite
|
||||
GL_MAP_READ_BIT, // nzBufferAccess_ReadOnly
|
||||
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");
|
||||
|
|
@ -1889,11 +1890,10 @@ static_assert(sizeof(NzOpenGL::BufferTargetBinding)/sizeof(GLenum) == nzBufferTy
|
|||
|
||||
GLenum NzOpenGL::BufferUsage[] =
|
||||
{
|
||||
// J'ai choisi DYNAMIC à la place de STREAM car DYNAMIC semble plus adapté au profil "une mise à jour pour quelques rendus"
|
||||
// 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/discussion_boards/ubbthreads.php?ubb=showflat&Number=160839
|
||||
GL_DYNAMIC_DRAW, // nzBufferUsage_Dynamic
|
||||
GL_STATIC_DRAW // nzBufferUsage_Static
|
||||
// D'après la documentation, GL_STREAM_DRAW semble être plus adapté à notre cas (ratio modification/rendu 1:2-3)
|
||||
// Source: http://www.opengl.org/sdk/docs/man/html/glBufferData.xhtml
|
||||
GL_STREAM_DRAW, // nzBufferUsage_Dynamic
|
||||
GL_STATIC_DRAW // nzBufferUsage_Static
|
||||
};
|
||||
|
||||
static_assert(sizeof(NzOpenGL::BufferUsage)/sizeof(GLenum) == nzBufferUsage_Max+1, "Buffer usage array is incomplete");
|
||||
|
|
|
|||
Loading…
Reference in New Issue