Changeset View
Changeset View
Standalone View
Standalone View
source/renderer/VertexBuffer.cpp
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target) | ||||
} | } | ||||
// store max/free vertex counts | // store max/free vertex counts | ||||
m_MaxVertices = m_FreeVertices = size / vertexSize; | m_MaxVertices = m_FreeVertices = size / vertexSize; | ||||
// allocate raw buffer | // allocate raw buffer | ||||
if (g_Renderer.m_Caps.m_VBO) | if (g_Renderer.m_Caps.m_VBO) | ||||
{ | { | ||||
pglGenBuffersARB(1, &m_Handle); | glGenBuffers(1, &m_Handle); | ||||
pglBindBufferARB(m_Target, m_Handle); | glBindBuffer(m_Target, m_Handle); | ||||
pglBufferDataARB(m_Target, m_MaxVertices * m_VertexSize, 0, m_Usage); | glBufferData(m_Target, m_MaxVertices * m_VertexSize, 0, m_Usage); | ||||
pglBindBufferARB(m_Target, 0); | glBindBuffer(m_Target, 0); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
m_SysMem = new u8[m_MaxVertices * m_VertexSize]; | m_SysMem = new u8[m_MaxVertices * m_VertexSize]; | ||||
} | } | ||||
// create sole free chunk | // create sole free chunk | ||||
VBChunk* chunk = new VBChunk; | VBChunk* chunk = new VBChunk; | ||||
chunk->m_Owner = this; | chunk->m_Owner = this; | ||||
chunk->m_Count = m_FreeVertices; | chunk->m_Count = m_FreeVertices; | ||||
chunk->m_Index = 0; | chunk->m_Index = 0; | ||||
m_FreeList.push_front(chunk); | m_FreeList.push_front(chunk); | ||||
} | } | ||||
CVertexBuffer::~CVertexBuffer() | CVertexBuffer::~CVertexBuffer() | ||||
{ | { | ||||
// Must have released all chunks before destroying the buffer | // Must have released all chunks before destroying the buffer | ||||
ENSURE(m_AllocList.empty()); | ENSURE(m_AllocList.empty()); | ||||
if (m_Handle) | if (m_Handle) | ||||
pglDeleteBuffersARB(1, &m_Handle); | glDeleteBuffers(1, &m_Handle); | ||||
delete[] m_SysMem; | delete[] m_SysMem; | ||||
typedef std::list<VBChunk*>::iterator Iter; | typedef std::list<VBChunk*>::iterator Iter; | ||||
for (Iter iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) | for (Iter iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) | ||||
delete *iter; | delete *iter; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | if (UseStreaming(m_Usage)) | ||||
chunk->m_Dirty = true; | chunk->m_Dirty = true; | ||||
// Sanity check: Make sure the caller hasn't tried to reallocate | // Sanity check: Make sure the caller hasn't tried to reallocate | ||||
// their backing store | // their backing store | ||||
ENSURE(data == chunk->m_BackingStore); | ENSURE(data == chunk->m_BackingStore); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
pglBindBufferARB(m_Target, m_Handle); | glBindBuffer(m_Target, m_Handle); | ||||
pglBufferSubDataARB(m_Target, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize, data); | glBufferSubData(m_Target, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize, data); | ||||
pglBindBufferARB(m_Target, 0); | glBindBuffer(m_Target, 0); | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
ENSURE(m_SysMem); | ENSURE(m_SysMem); | ||||
memcpy(m_SysMem + chunk->m_Index * m_VertexSize, data, chunk->m_Count * m_VertexSize); | memcpy(m_SysMem + chunk->m_Index * m_VertexSize, data, chunk->m_Count * m_VertexSize); | ||||
} | } | ||||
} | } | ||||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
// Bind: bind to this buffer; return pointer to address required as parameter | // Bind: bind to this buffer; return pointer to address required as parameter | ||||
// to glVertexPointer ( + etc) calls | // to glVertexPointer ( + etc) calls | ||||
u8* CVertexBuffer::Bind() | u8* CVertexBuffer::Bind() | ||||
{ | { | ||||
if (!g_Renderer.m_Caps.m_VBO) | if (!g_Renderer.m_Caps.m_VBO) | ||||
return m_SysMem; | return m_SysMem; | ||||
pglBindBufferARB(m_Target, m_Handle); | glBindBuffer(m_Target, m_Handle); | ||||
if (UseStreaming(m_Usage)) | if (UseStreaming(m_Usage)) | ||||
{ | { | ||||
// If any chunks are out of sync with the current VBO, and are | // If any chunks are out of sync with the current VBO, and are | ||||
// needed for rendering this frame, we'll need to re-upload the VBO | // needed for rendering this frame, we'll need to re-upload the VBO | ||||
bool needUpload = false; | bool needUpload = false; | ||||
for (VBChunk* const& chunk : m_AllocList) | for (VBChunk* const& chunk : m_AllocList) | ||||
{ | { | ||||
if (chunk->m_Dirty && chunk->m_Needed) | if (chunk->m_Dirty && chunk->m_Needed) | ||||
{ | { | ||||
needUpload = true; | needUpload = true; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (needUpload) | if (needUpload) | ||||
{ | { | ||||
// Tell the driver that it can reallocate the whole VBO | // Tell the driver that it can reallocate the whole VBO | ||||
pglBufferDataARB(m_Target, m_MaxVertices * m_VertexSize, NULL, m_Usage); | glBufferData(m_Target, m_MaxVertices * m_VertexSize, NULL, m_Usage); | ||||
// (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used | // (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used | ||||
// here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with | // here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with | ||||
// current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do | // current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do | ||||
// the explicit glBufferData.) | // the explicit glBufferData.) | ||||
while (true) | while (true) | ||||
{ | { | ||||
void* p = pglMapBufferARB(m_Target, GL_WRITE_ONLY); | void* p = glMapBuffer(m_Target, GL_WRITE_ONLY); | ||||
if (p == NULL) | if (p == NULL) | ||||
{ | { | ||||
// This shouldn't happen unless we run out of virtual address space | // This shouldn't happen unless we run out of virtual address space | ||||
LOGERROR("glMapBuffer failed"); | LOGERROR("glMapBuffer failed"); | ||||
break; | break; | ||||
} | } | ||||
#ifndef NDEBUG | #ifndef NDEBUG | ||||
// To help detect bugs where PrepareForRendering() was not called, | // To help detect bugs where PrepareForRendering() was not called, | ||||
// force all not-needed data to 0, so things won't get rendered | // force all not-needed data to 0, so things won't get rendered | ||||
// with undefined (but possibly still correct-looking) data. | // with undefined (but possibly still correct-looking) data. | ||||
memset(p, 0, m_MaxVertices * m_VertexSize); | memset(p, 0, m_MaxVertices * m_VertexSize); | ||||
#endif | #endif | ||||
// Copy only the chunks we need. (This condition is helpful when | // Copy only the chunks we need. (This condition is helpful when | ||||
// the VBO contains data for every unit in the world, but only a | // the VBO contains data for every unit in the world, but only a | ||||
// handful are visible on screen and we don't need to bother copying | // handful are visible on screen and we don't need to bother copying | ||||
// the rest.) | // the rest.) | ||||
for (VBChunk* const& chunk : m_AllocList) | for (VBChunk* const& chunk : m_AllocList) | ||||
if (chunk->m_Needed) | if (chunk->m_Needed) | ||||
memcpy((u8 *)p + chunk->m_Index * m_VertexSize, chunk->m_BackingStore, chunk->m_Count * m_VertexSize); | memcpy((u8 *)p + chunk->m_Index * m_VertexSize, chunk->m_BackingStore, chunk->m_Count * m_VertexSize); | ||||
if (pglUnmapBufferARB(m_Target) == GL_TRUE) | if (glUnmapBuffer(m_Target) == GL_TRUE) | ||||
break; | break; | ||||
// Unmap might fail on e.g. resolution switches, so just try again | // Unmap might fail on e.g. resolution switches, so just try again | ||||
// and hope it will eventually succeed | // and hope it will eventually succeed | ||||
debug_printf("glUnmapBuffer failed, trying again...\n"); | debug_printf("glUnmapBuffer failed, trying again...\n"); | ||||
} | } | ||||
// Anything we just uploaded is clean; anything else is dirty | // Anything we just uploaded is clean; anything else is dirty | ||||
Show All 22 Lines | u8* CVertexBuffer::GetBindAddress() | ||||
else | else | ||||
return m_SysMem; | return m_SysMem; | ||||
} | } | ||||
void CVertexBuffer::Unbind() | void CVertexBuffer::Unbind() | ||||
{ | { | ||||
if (g_Renderer.m_Caps.m_VBO) | if (g_Renderer.m_Caps.m_VBO) | ||||
{ | { | ||||
pglBindBufferARB(GL_ARRAY_BUFFER, 0); | glBindBuffer(GL_ARRAY_BUFFER, 0); | ||||
pglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | ||||
} | } | ||||
} | } | ||||
size_t CVertexBuffer::GetBytesReserved() const | size_t CVertexBuffer::GetBytesReserved() const | ||||
{ | { | ||||
return MAX_VB_SIZE_BYTES; | return MAX_VB_SIZE_BYTES; | ||||
} | } | ||||
Show All 23 Lines |
Wildfire Games · Phabricator