Updated LLVertexBuffer to match v3 a bit better. Let's see how it fares.
This commit is contained in:
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user