Newer
Older
/**
* @file llvertexbuffer.cpp
* @brief LLVertexBuffer implementation
*
* $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
#include "linden_common.h"
#include "llfasttimer.h"
#include "llsys.h"
#include "llvertexbuffer.h"
// #include "llrender.h"
#include "llglheaders.h"
#include "llrender.h"
David Parks
committed
#include "llshadermgr.h"
#include "llglslshader.h"
//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
U32 nhpo2(U32 v)
{
U32 r = 1;
while (r < v) {
r *= 2;
}
return r;
}
//which power of 2 is i?
//assumes i is a power of 2 > 0
U32 wpo2(U32 i)
{
llassert(i > 0);
llassert(nhpo2(i) == i);
U32 r = 0;
while (i >>= 1) ++r;
return r;
}
const U32 LL_VBO_BLOCK_SIZE = 2048;
David Parks
committed
const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024;
U32 vbo_block_size(U32 size)
{ //what block size will fit size?
U32 mod = size % LL_VBO_BLOCK_SIZE;
return mod == 0 ? size : size + (LL_VBO_BLOCK_SIZE-mod);
}
U32 vbo_block_index(U32 size)
{
return vbo_block_size(size)/LL_VBO_BLOCK_SIZE;
}
David Parks
committed
const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE);
//============================================================================
//static
Leslie Linden
committed
LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
U32 LLVBOPool::sBytesPooled = 0;
U32 LLVBOPool::sIndexBytesPooled = 0;
David Parks
committed
U32 LLVBOPool::sCurGLName = 1;
std::list<U32> LLVertexBuffer::sAvailableVAOName;
U32 LLVertexBuffer::sCurVAOName = 1;
U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
U32 LLVertexBuffer::sIndexCount = 0;
Leslie Linden
committed
LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL;
U32 LLVertexBuffer::sBindCount = 0;
U32 LLVertexBuffer::sSetCount = 0;
S32 LLVertexBuffer::sCount = 0;
S32 LLVertexBuffer::sGLCount = 0;
S32 LLVertexBuffer::sMappedCount = 0;
bool LLVertexBuffer::sDisableVBOMapping = false;
bool LLVertexBuffer::sEnableVBOs = true;
Josh Bell
committed
U32 LLVertexBuffer::sGLRenderBuffer = 0;
U32 LLVertexBuffer::sGLRenderArray = 0;
Josh Bell
committed
U32 LLVertexBuffer::sGLRenderIndices = 0;
U32 LLVertexBuffer::sLastMask = 0;
bool LLVertexBuffer::sVBOActive = false;
bool LLVertexBuffer::sIBOActive = false;
U32 LLVertexBuffer::sAllocatedBytes = 0;
U32 LLVertexBuffer::sVertexCount = 0;
bool LLVertexBuffer::sMapped = false;
bool LLVertexBuffer::sUseStreamDraw = true;
bool LLVertexBuffer::sUseVAO = false;
bool LLVertexBuffer::sPreferStreamDraw = false;
David Parks
committed
David Parks
committed
U32 LLVBOPool::genBuffer()
David Parks
committed
{
David Parks
committed
U32 ret = 0;
David Parks
committed
David Parks
committed
if (mGLNamePool.empty())
David Parks
committed
{
David Parks
committed
ret = sCurGLName++;
David Parks
committed
}
David Parks
committed
else
David Parks
committed
{
David Parks
committed
ret = mGLNamePool.front();
mGLNamePool.pop_front();
David Parks
committed
}
David Parks
committed
return ret;
}
void LLVBOPool::deleteBuffer(U32 name)
{
if (gGLManager.mInited)
{
LLVertexBuffer::unbind();
David Parks
committed
glBindBufferARB(mType, name);
glBufferDataARB(mType, 0, NULL, mUsage);
David Parks
committed
llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end());
David Parks
committed
mGLNamePool.push_back(name);
David Parks
committed
glBindBufferARB(mType, 0);
David Parks
committed
}
David Parks
committed
David Parks
committed
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);
volatile U8* ret = NULL;
U32 i = vbo_block_index(size);
if (mFreeList.size() <= i)
{
mFreeList.resize(i+1);
}
David Parks
committed
if (mFreeList[i].empty() || for_seed)
{
//make a new buffer
name = genBuffer();
glBindBufferARB(mType, name);
David Parks
committed
if (!for_seed && i < LL_VBO_POOL_SEED_COUNT)
{ //record this miss
mMissCount[i]++;
}
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);
David Parks
committed
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
{
name = mFreeList[i].front().mGLName;
ret = mFreeList[i].front().mClientData;
if (mType == GL_ARRAY_BUFFER_ARB)
{
sBytesPooled -= size;
}
else
{
sIndexBytesPooled -= size;
}
mFreeList[i].pop_front();
}
return ret;
}
void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
llassert(vbo_block_size(size) == size);
David Parks
committed
deleteBuffer(name);
ll_aligned_free_16((U8*) buffer);
if (mType == GL_ARRAY_BUFFER_ARB)
{
LLVertexBuffer::sAllocatedBytes -= size;
}
else
{
LLVertexBuffer::sAllocatedIndexBytes -= size;
}
}
David Parks
committed
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 (U32 j = 0; j < count; ++j)
{
allocate(dummy_name, size, true);
}
}
}
}
simon@Simon-PC.lindenlab.com
committed
void LLVBOPool::cleanup()
{
David Parks
committed
U32 size = LL_VBO_BLOCK_SIZE;
for (U32 i = 0; i < mFreeList.size(); ++i)
{
record_list_t& l = mFreeList[i];
while (!l.empty())
{
Record& r = l.front();
David Parks
committed
deleteBuffer(r.mGLName);
if (r.mClientData)
{
ll_aligned_free_16((void*) r.mClientData);
}
l.pop_front();
if (mType == GL_ARRAY_BUFFER_ARB)
{
sBytesPooled -= size;
LLVertexBuffer::sAllocatedBytes -= size;
}
else
{
sIndexBytesPooled -= size;
LLVertexBuffer::sAllocatedIndexBytes -= size;
}
}
David Parks
committed
size += LL_VBO_BLOCK_SIZE;
David Parks
committed
//reset miss counts
std::fill(mMissCount.begin(), mMissCount.end(), 0);
}
David Parks
committed
//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
sizeof(LLVector4), // TYPE_VERTEX,
sizeof(LLVector4), // TYPE_NORMAL,
sizeof(LLVector2), // TYPE_TEXCOORD0,
sizeof(LLVector2), // TYPE_TEXCOORD1,
sizeof(LLVector2), // TYPE_TEXCOORD2,
sizeof(LLVector2), // TYPE_TEXCOORD3,
sizeof(LLColor4U), // TYPE_COLOR,
David Parks
committed
sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
David Parks
committed
sizeof(LLVector4), // TYPE_TANGENT,
sizeof(F32), // TYPE_WEIGHT,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
static std::string vb_type_name[] =
{
"TYPE_VERTEX",
"TYPE_NORMAL",
"TYPE_TEXCOORD0",
"TYPE_TEXCOORD1",
"TYPE_TEXCOORD2",
"TYPE_TEXCOORD3",
"TYPE_COLOR",
"TYPE_EMISSIVE",
David Parks
committed
"TYPE_TANGENT",
"TYPE_WEIGHT",
"TYPE_WEIGHT4",
"TYPE_CLOTHWEIGHT",
"TYPE_TEXTURE_INDEX",
"TYPE_MAX",
"TYPE_INDEX",
};
U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
{
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_QUADS,
GL_LINE_LOOP,
David Parks
committed
//static
U32 LLVertexBuffer::getVAOName()
{
U32 ret = 0;
if (!sAvailableVAOName.empty())
{
ret = sAvailableVAOName.front();
sAvailableVAOName.pop_front();
}
else
{
David Parks
committed
glGenVertexArrays(1, &ret);
David Parks
committed
}
return ret;
}
//static
void LLVertexBuffer::releaseVAOName(U32 name)
{
sAvailableVAOName.push_back(name);
}
David Parks
committed
//static
void LLVertexBuffer::seedPools()
{
sStreamVBOPool.seedPool();
sDynamicVBOPool.seedPool();
sStreamIBOPool.seedPool();
sDynamicIBOPool.seedPool();
}
void LLVertexBuffer::setupClientArrays(U32 data_mask)
David Parks
committed
if (sLastMask != data_mask)
David Parks
committed
David Parks
committed
if (gGLManager.mGLSLVersionMajor < 2 && gGLManager.mGLSLVersionMinor < 30)
{
//make sure texture index is disabled
data_mask = data_mask & ~MAP_TEXTURE_INDEX;
}
if (LLGLSLShader::sNoFixedFunction)
{
for (U32 i = 0; i < TYPE_MAX; ++i)
S32 loc = i;
U32 mask = 1 << i;
if (sLastMask & (1 << i))
{ //was enabled
if (!(data_mask & mask))
{ //needs to be disabled
glDisableVertexAttribArrayARB(loc);
}
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
}
else
{ //was disabled
if (data_mask & mask)
{ //needs to be enabled
glEnableVertexAttribArrayARB(loc);
}
}
}
}
else
{
GLenum array[] =
{
GL_VERTEX_ARRAY,
GL_NORMAL_ARRAY,
GL_TEXTURE_COORD_ARRAY,
GL_COLOR_ARRAY,
};
GLenum mask[] =
{
MAP_VERTEX,
MAP_NORMAL,
MAP_TEXCOORD0,
MAP_COLOR
};
for (U32 i = 0; i < 4; ++i)
{
if (sLastMask & mask[i])
{ //was enabled
if (!(data_mask & mask[i]))
{ //needs to be disabled
glDisableClientState(array[i]);
}
else if (gDebugGL)
{ //needs to be enabled, make sure it was (DEBUG)
if (!glIsEnabled(array[i]))
{
if (gDebugSession)
{
gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
}
else
{
llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
}
}
}
else
{ //was disabled
if (data_mask & mask[i])
{ //needs to be enabled
glEnableClientState(array[i]);
}
else if (gDebugGL && glIsEnabled(array[i]))
{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
if (gDebugSession)
{
gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
}
else
{
llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
U32 map_tc[] =
{
MAP_TEXCOORD1,
MAP_TEXCOORD2,
MAP_TEXCOORD3
};
David Parks
committed
for (U32 i = 0; i < 3; i++)
if (sLastMask & map_tc[i])
{
if (!(data_mask & map_tc[i]))
{ //disable
glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
else if (data_mask & map_tc[i])
{
glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
David Parks
committed
if (sLastMask & MAP_TANGENT)
David Parks
committed
if (!(data_mask & MAP_TANGENT))
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
David Parks
committed
else if (data_mask & MAP_TANGENT)
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
David Parks
committed
sLastMask = data_mask;
static LLFastTimer::DeclareTimer FTM_VB_DRAW_ARRAYS("drawArrays");
void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
LLFastTimer t(FTM_VB_DRAW_ARRAYS);
David Parks
committed
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
gGL.syncMatrices();
David Parks
committed
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();
setupClientArrays(MAP_VERTEX | MAP_NORMAL);
David Parks
committed
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (shader)
{
David Parks
committed
S32 loc = LLVertexBuffer::TYPE_VERTEX;
David Parks
committed
if (loc > -1)
{
glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
}
David Parks
committed
loc = LLVertexBuffer::TYPE_NORMAL;
David Parks
committed
if (loc > -1)
{
glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
}
}
else
{
glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
glNormalPointer(GL_FLOAT, 0, norm[0].mV);
}
David Parks
committed
LLGLSLShader::startProfile();
glDrawArrays(sGLMode[mode], 0, count);
David Parks
committed
LLGLSLShader::stopProfile(count, mode);
David Parks
committed
//static
void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
{
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
gGL.syncMatrices();
David Parks
committed
U32 mask = LLVertexBuffer::MAP_VERTEX;
if (tc)
{
mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
}
unbind();
setupClientArrays(mask);
David Parks
committed
if (LLGLSLShader::sNoFixedFunction)
David Parks
committed
{
David Parks
committed
S32 loc = LLVertexBuffer::TYPE_VERTEX;
glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
David Parks
committed
David Parks
committed
if (tc)
{
loc = LLVertexBuffer::TYPE_TEXCOORD0;
glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
David Parks
committed
}
}
else
{
glTexCoordPointer(2, GL_FLOAT, 0, tc);
glVertexPointer(3, GL_FLOAT, 16, pos);
}
David Parks
committed
LLGLSLShader::startProfile();
David Parks
committed
glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
David Parks
committed
LLGLSLShader::stopProfile(num_indices, mode);
David Parks
committed
}
void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
if (start >= (U32) mNumVerts ||
end >= (U32) mNumVerts)
llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl;
llassert(mNumIndices >= 0);
if (indices_offset >= (U32) mNumIndices ||
indices_offset + count > (U32) mNumIndices)
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
if (gDebugGL && !useVBOs())
{
U16* idx = ((U16*) getIndicesPointer())+indices_offset;
for (U32 i = 0; i < count; ++i)
{
if (idx[i] < start || idx[i] > end)
{
llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
}
}
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (shader && shader->mFeatures.mIndexedTextureChannels > 1)
{
LLStrider<LLVector4a> v;
//hack to get non-const reference
LLVertexBuffer* vb = (LLVertexBuffer*) this;
vb->getVertexStrider(v);
for (U32 i = start; i < end; i++)
{
S32 idx = (S32) (v[i][3]+0.25f);
if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels)
{
llerrs << "Bad texture index found in vertex data stream." << llendl;
}
}
}
}
}
void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
{
validateRange(start, end, count, indices_offset);
Leslie Linden
committed
mMappable = false;
gGL.syncMatrices();
llassert(mNumVerts >= 0);
David Parks
committed
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
David Parks
committed
if (mGLArray)
David Parks
committed
if (mGLArray != sGLRenderArray)
{
llerrs << "Wrong vertex array bound." << llendl;
}
David Parks
committed
else
{
if (mGLIndices != sGLRenderIndices)
{
llerrs << "Wrong index buffer bound." << llendl;
}
David Parks
committed
if (mGLBuffer != sGLRenderBuffer)
{
llerrs << "Wrong vertex buffer bound." << llendl;
}
}
if (gDebugGL && !mGLArray && useVBOs())
David Parks
committed
GLint elem = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
if (elem != mGLIndices)
{
llerrs << "Wrong index buffer bound!" << llendl;
}
{
llerrs << "Invalid draw mode: " << mode << llendl;
stop_glerror();
David Parks
committed
LLGLSLShader::startProfile();
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
David Parks
committed
LLGLSLShader::stopProfile(count, mode);
David Parks
committed
David Parks
committed
placeFence();
}
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
David Parks
committed
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
Leslie Linden
committed
mMappable = false;
gGL.syncMatrices();
llassert(mNumIndices >= 0);
if (indices_offset >= (U32) mNumIndices ||
indices_offset + count > (U32) mNumIndices)
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
David Parks
committed
if (mGLArray)
David Parks
committed
if (mGLArray != sGLRenderArray)
{
llerrs << "Wrong vertex array bound." << llendl;
}
David Parks
committed
else
David Parks
committed
if (mGLIndices != sGLRenderIndices)
{
llerrs << "Wrong index buffer bound." << llendl;
}
if (mGLBuffer != sGLRenderBuffer)
{
llerrs << "Wrong vertex buffer bound." << llendl;
}
{
llerrs << "Invalid draw mode: " << mode << llendl;
stop_glerror();
David Parks
committed
LLGLSLShader::startProfile();
glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
((U16*) getIndicesPointer()) + indices_offset);
David Parks
committed
LLGLSLShader::stopProfile(count, mode);
stop_glerror();
David Parks
committed
placeFence();
static LLFastTimer::DeclareTimer FTM_GL_DRAW_ARRAYS("GL draw arrays");
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{
David Parks
committed
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
Leslie Linden
committed
mMappable = false;
gGL.syncMatrices();
llassert(mNumVerts >= 0);
if (first >= (U32) mNumVerts ||
first + count > (U32) mNumVerts)
{
llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
}
David Parks
committed
if (mGLArray)
David Parks
committed
if (mGLArray != sGLRenderArray)
{
llerrs << "Wrong vertex array bound." << llendl;
}
}
else
{
if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
{
llerrs << "Wrong vertex buffer bound." << llendl;
}
{
llerrs << "Invalid draw mode: " << mode << llendl;
{
LLFastTimer t2(FTM_GL_DRAW_ARRAYS);
stop_glerror();
David Parks
committed
LLGLSLShader::startProfile();
glDrawArrays(sGLMode[mode], first, count);
David Parks
committed
LLGLSLShader::stopProfile(count, mode);
David Parks
committed
placeFence();
Xiaohong Bao
committed
void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
Leslie Linden
committed
sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject;
sDisableVBOMapping = sEnableVBOs && no_vbo_mapping;
Leslie Linden
committed
if (!sPrivatePoolp)
Leslie Linden
committed
sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC);
}
//static
void LLVertexBuffer::unbind()
{
if (sGLRenderArray)
{
glBindVertexArray(0);
sGLRenderArray = 0;
David Parks
committed
sGLRenderIndices = 0;
}
if (sVBOActive)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
if (sIBOActive)
{
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
sGLRenderBuffer = 0;
sGLRenderIndices = 0;
}
//static
void LLVertexBuffer::cleanupClass()
{
sStreamIBOPool.cleanup();
sDynamicIBOPool.cleanup();
sStreamVBOPool.cleanup();
sDynamicVBOPool.cleanup();
LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp);
sPrivatePoolp = NULL;
}
//----------------------------------------------------------------------------
Leslie Linden
committed
S32 LLVertexBuffer::determineUsage(S32 usage)
Leslie Linden
committed
S32 ret_usage = usage;
if (!sEnableVBOs)
{
Leslie Linden
committed
ret_usage = 0;
Leslie Linden
committed
if (ret_usage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
Leslie Linden
committed
ret_usage = 0;
if (ret_usage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
Leslie Linden
committed
ret_usage = GL_STREAM_DRAW_ARB;
Leslie Linden
committed
if (ret_usage == 0 && LLRender::sGLCoreProfile)
{ //MUST use VBOs for all rendering
Leslie Linden
committed
ret_usage = GL_STREAM_DRAW_ARB;
}
Leslie Linden
committed
if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB)
{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
if (sDisableVBOMapping)
{ //always use stream draw if VBO mapping is disabled
Leslie Linden
committed
ret_usage = GL_STREAM_DRAW_ARB;
}
else
{
Leslie Linden
committed
ret_usage = GL_DYNAMIC_DRAW_ARB;
}
Leslie Linden
committed
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
return ret_usage;
}
LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
LLRefCount(),
mNumVerts(0),
mNumIndices(0),
mAlignedOffset(0),
mAlignedIndexOffset(0),
mSize(0),
mIndicesSize(0),
mTypeMask(typemask),
mUsage(LLVertexBuffer::determineUsage(usage)),
mGLBuffer(0),
mGLIndices(0),
mGLArray(0),
mMappedData(NULL),
mMappedIndexData(NULL),
mMappedDataUsingVBOs(false),
mMappedIndexDataUsingVBOs(false),
mVertexLocked(false),
mIndexLocked(false),
mFinal(false),
mEmpty(true),
mMappable(false),
mFence(NULL)
{
mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping);
//zero out offsets
for (U32 i = 0; i < TYPE_MAX; i++)
{
mOffsets[i] = 0;
}
sCount++;
}
//static
S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)