Updated LLVertexBuffer to match v3 a bit better. Let's see how it fares.

This commit is contained in:
Shyotl
2013-05-16 01:42:45 -05:00
parent be29088103
commit 2bdd695d5f
2 changed files with 192 additions and 80 deletions

View File

@@ -36,9 +36,6 @@
#include "llshadermgr.h" #include "llshadermgr.h"
#include "llglslshader.h" #include "llglslshader.h"
#include "llmemory.h" #include "llmemory.h"
#include "llfasttimer.h"
#define LL_VBO_POOLING 0
//Next Highest Power Of Two //Next Highest Power Of Two
//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
@@ -67,6 +64,7 @@ U32 wpo2(U32 i)
const U32 LL_VBO_BLOCK_SIZE = 2048; const U32 LL_VBO_BLOCK_SIZE = 2048;
const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024;
U32 vbo_block_size(U32 size) U32 vbo_block_size(U32 size)
{ //what block size will fit size? { //what block size will fit size?
@@ -79,6 +77,7 @@ U32 vbo_block_index(U32 size)
return vbo_block_size(size)/LL_VBO_BLOCK_SIZE; return vbo_block_size(size)/LL_VBO_BLOCK_SIZE;
} }
const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE);
//============================================================================ //============================================================================
@@ -91,6 +90,11 @@ LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_
U32 LLVBOPool::sBytesPooled = 0; U32 LLVBOPool::sBytesPooled = 0;
U32 LLVBOPool::sIndexBytesPooled = 0; U32 LLVBOPool::sIndexBytesPooled = 0;
U32 LLVBOPool::sCurGLName = 1;
std::list<U32> LLVertexBuffer::sAvailableVAOName;
U32 LLVertexBuffer::sCurVAOName = 1;
U32 LLVertexBuffer::sAllocatedIndexBytes = 0; U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
U32 LLVertexBuffer::sIndexCount = 0; U32 LLVertexBuffer::sIndexCount = 0;
@@ -116,14 +120,54 @@ bool LLVertexBuffer::sUseVAO = false;
bool LLVertexBuffer::sPreferStreamDraw = false; bool LLVertexBuffer::sPreferStreamDraw = false;
volatile U8* LLVBOPool::allocate(U32& name, U32 size) U32 LLVBOPool::genBuffer()
{
U32 ret = 0;
if (mGLNamePool.empty())
{
ret = sCurGLName++;
}
else
{
ret = mGLNamePool.front();
mGLNamePool.pop_front();
}
return ret;
}
void LLVBOPool::deleteBuffer(U32 name)
{
if (gGLManager.mInited)
{
LLVertexBuffer::unbind();
glBindBufferARB(mType, name);
glBufferDataARB(mType, 0, NULL, mUsage);
llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end());
mGLNamePool.push_back(name);
glBindBufferARB(mType, 0);
}
}
LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
: mUsage(vboUsage), mType(vboType)
{
mMissCount.resize(LL_VBO_POOL_SEED_COUNT);
std::fill(mMissCount.begin(), mMissCount.end(), 0);
}
volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
{ {
llassert(vbo_block_size(size) == size); llassert(vbo_block_size(size) == size);
volatile U8* ret = NULL; volatile U8* ret = NULL;
#if LL_VBO_POOLING
U32 i = vbo_block_index(size); U32 i = vbo_block_index(size);
if (mFreeList.size() <= i) if (mFreeList.size() <= i)
@@ -131,12 +175,18 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
mFreeList.resize(i+1); mFreeList.resize(i+1);
} }
if (mFreeList[i].empty()) if (mFreeList[i].empty() || for_seed)
{ {
//make a new buffer //make a new buffer
glGenBuffersARB(1, &name); name = genBuffer();
glBindBufferARB(mType, name); glBindBufferARB(mType, name);
if (!for_seed && i < LL_VBO_POOL_SEED_COUNT)
{ //record this miss
mMissCount[i]++;
}
if (mType == GL_ARRAY_BUFFER_ARB) if (mType == GL_ARRAY_BUFFER_ARB)
{ {
LLVertexBuffer::sAllocatedBytes += size; LLVertexBuffer::sAllocatedBytes += size;
@@ -157,6 +207,25 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
} }
glBindBufferARB(mType, 0); glBindBufferARB(mType, 0);
if (for_seed)
{ //put into pool for future use
llassert(mFreeList.size() > i);
Record rec;
rec.mGLName = name;
rec.mClientData = ret;
if (mType == GL_ARRAY_BUFFER_ARB)
{
sBytesPooled += size;
}
else
{
sIndexBytesPooled += size;
}
mFreeList[i].push_back(rec);
}
} }
else else
{ {
@@ -174,33 +243,6 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
mFreeList[i].pop_front(); mFreeList[i].pop_front();
} }
#else //no pooling
glGenBuffersARB(1, &name);
glBindBufferARB(mType, name);
if (mType == GL_ARRAY_BUFFER_ARB)
{
LLVertexBuffer::sAllocatedBytes += size;
}
else
{
LLVertexBuffer::sAllocatedIndexBytes += size;
}
if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
{
glBufferDataARB(mType, size, 0, mUsage);
ret = (U8*) ll_aligned_malloc_16(size);
}
else
{ //always use a true hint of static draw when allocating non-client-backed buffers
glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB);
}
glBindBufferARB(mType, 0);
#endif
return ret; return ret;
} }
@@ -209,34 +251,7 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
{ {
llassert(vbo_block_size(size) == size); llassert(vbo_block_size(size) == size);
#if LL_VBO_POOLING deleteBuffer(name);
U32 i = vbo_block_index(size);
llassert(mFreeList.size() > i);
Record rec;
rec.mGLName = name;
rec.mClientData = buffer;
if (buffer == NULL)
{
glDeleteBuffersARB(1, &rec.mGLName);
}
else
{
if (mType == GL_ARRAY_BUFFER_ARB)
{
sBytesPooled += size;
}
else
{
sIndexBytesPooled += size;
}
mFreeList[i].push_back(rec);
}
#else //no pooling
glDeleteBuffersARB(1, &name);
ll_aligned_free_16((U8*) buffer); ll_aligned_free_16((U8*) buffer);
if (mType == GL_ARRAY_BUFFER_ARB) if (mType == GL_ARRAY_BUFFER_ARB)
@@ -247,12 +262,37 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
{ {
LLVertexBuffer::sAllocatedIndexBytes -= size; LLVertexBuffer::sAllocatedIndexBytes -= size;
} }
#endif
} }
void LLVBOPool::seedPool()
{
U32 dummy_name = 0;
if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
{
mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
}
for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++)
{
if (mMissCount[i] > mFreeList[i].size())
{
U32 size = i*LL_VBO_BLOCK_SIZE;
S32 count = mMissCount[i] - mFreeList[i].size();
for (S32 j = 0; j < count; ++j)
{
allocate(dummy_name, size, true);
}
}
}
}
void LLVBOPool::cleanup() void LLVBOPool::cleanup()
{ {
U32 size = 1; U32 size = LL_VBO_BLOCK_SIZE;
for (U32 i = 0; i < mFreeList.size(); ++i) for (U32 i = 0; i < mFreeList.size(); ++i)
{ {
@@ -262,8 +302,8 @@ void LLVBOPool::cleanup()
{ {
Record& r = l.front(); Record& r = l.front();
glDeleteBuffersARB(1, &r.mGLName); deleteBuffer(r.mGLName);
if (r.mClientData) if (r.mClientData)
{ {
ll_aligned_free_16((void*) r.mClientData); ll_aligned_free_16((void*) r.mClientData);
@@ -283,8 +323,11 @@ void LLVBOPool::cleanup()
} }
} }
size *= 2; size += LL_VBO_BLOCK_SIZE;
} }
//reset miss counts
std::fill(mMissCount.begin(), mMissCount.end(), 0);
} }
@@ -318,6 +361,41 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
GL_LINE_LOOP, GL_LINE_LOOP,
}; };
//static
U32 LLVertexBuffer::getVAOName()
{
U32 ret = 0;
if (!sAvailableVAOName.empty())
{
ret = sAvailableVAOName.front();
sAvailableVAOName.pop_front();
}
else
{
#ifdef GL_ARB_vertex_array_object
glGenVertexArrays(1, &ret);
#endif
}
return ret;
}
//static
void LLVertexBuffer::releaseVAOName(U32 name)
{
sAvailableVAOName.push_back(name);
}
//static
void LLVertexBuffer::seedPools()
{
sStreamVBOPool.seedPool();
sDynamicVBOPool.seedPool();
sStreamIBOPool.seedPool();
sDynamicIBOPool.seedPool();
}
//static //static
void LLVertexBuffer::setupClientArrays(U32 data_mask) void LLVertexBuffer::setupClientArrays(U32 data_mask)
@@ -473,8 +551,21 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, con
gGL.syncMatrices(); gGL.syncMatrices();
U32 count = pos.size(); U32 count = pos.size();
llassert_always(norm.size() >= pos.size());
llassert_always(count > 0); llassert(norm.size() >= pos.size());
llassert(count > 0);
if( count == 0 )
{
llwarns << "Called drawArrays with 0 vertices" << llendl;
return;
}
if( norm.size() < pos.size() )
{
llwarns << "Called drawArrays with #" << norm.size() << " normals and #" << pos.size() << " vertices" << llendl;
return;
}
unbind(); unbind();
@@ -690,6 +781,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
placeFence(); placeFence();
} }
static LLFastTimer::DeclareTimer FTM_GL_DRAW_ARRAYS("GL draw arrays");
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{ {
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
@@ -724,8 +816,11 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
return; return;
} }
stop_glerror(); {
glDrawArrays(sGLMode[mode], first, count); LLFastTimer t2(FTM_GL_DRAW_ARRAYS);
stop_glerror();
glDrawArrays(sGLMode[mode], first, count);
}
stop_glerror(); stop_glerror();
placeFence(); placeFence();
} }
@@ -920,7 +1015,7 @@ LLVertexBuffer::~LLVertexBuffer()
if (mGLArray) if (mGLArray)
{ {
#if GL_ARB_vertex_array_object #if GL_ARB_vertex_array_object
glDeleteVertexArrays(1, &mGLArray); releaseVAOName(mGLArray);
#endif #endif
} }
@@ -1193,7 +1288,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
{ {
#if GL_ARB_vertex_array_object #if GL_ARB_vertex_array_object
glGenVertexArrays(1, &mGLArray); mGLArray = getVAOName();
#endif #endif
setupVertexArray(); setupVertexArray();
} }

View File

@@ -56,24 +56,29 @@ class LLVBOPool
public: public:
static U32 sBytesPooled; static U32 sBytesPooled;
static U32 sIndexBytesPooled; static U32 sIndexBytesPooled;
static U32 sCurGLName;
LLVBOPool(U32 vboUsage, U32 vboType) LLVBOPool(U32 vboUsage, U32 vboType);
: mUsage(vboUsage)
, mType(vboType)
{}
const U32 mUsage; const U32 mUsage;
const U32 mType; const U32 mType;
//size MUST be a power of 2 //size MUST be a power of 2
volatile U8* allocate(U32& name, U32 size); volatile U8* allocate(U32& name, U32 size, bool for_seed = false);
//size MUST be the size provided to allocate that returned the given name //size MUST be the size provided to allocate that returned the given name
void release(U32 name, volatile U8* buffer, U32 size); void release(U32 name, volatile U8* buffer, U32 size);
//batch allocate buffers to be provided to the application on demand
void seedPool();
//destroy all records in mFreeList //destroy all records in mFreeList
void cleanup(); void cleanup();
U32 genBuffer();
void deleteBuffer(U32 name);
class Record class Record
{ {
public: public:
@@ -81,8 +86,12 @@ public:
volatile U8* mClientData; volatile U8* mClientData;
}; };
std::list<U32> mGLNamePool;
typedef std::list<Record> record_list_t; typedef std::list<Record> record_list_t;
std::vector<record_list_t> mFreeList; std::vector<record_list_t> mFreeList;
std::vector<U32> mMissCount;
}; };
@@ -119,10 +128,18 @@ public:
static LLVBOPool sStreamIBOPool; static LLVBOPool sStreamIBOPool;
static LLVBOPool sDynamicIBOPool; static LLVBOPool sDynamicIBOPool;
static std::list<U32> sAvailableVAOName;
static U32 sCurVAOName;
static bool sUseStreamDraw; static bool sUseStreamDraw;
static bool sUseVAO; static bool sUseVAO;
static bool sPreferStreamDraw; static bool sPreferStreamDraw;
static void seedPools();
static U32 getVAOName();
static void releaseVAOName(U32 name);
static void initClass(bool use_vbo, bool no_vbo_mapping); static void initClass(bool use_vbo, bool no_vbo_mapping);
static void cleanupClass(); static void cleanupClass();
static void setupClientArrays(U32 data_mask); static void setupClientArrays(U32 data_mask);