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 <boost/static_assert.hpp>
#include "llsys.h"
#include "llvertexbuffer.h"
// #include "llrender.h"
#include "llglheaders.h"
#include "llmemtype.h"
#include "llrender.h"
#include "llglslshader.h"
//============================================================================
//static
LLVBOPool LLVertexBuffer::sStreamVBOPool;
LLVBOPool LLVertexBuffer::sDynamicVBOPool;
LLVBOPool LLVertexBuffer::sStreamIBOPool;
LLVBOPool LLVertexBuffer::sDynamicIBOPool;
LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ;
U32 LLVertexBuffer::sBindCount = 0;
U32 LLVertexBuffer::sSetCount = 0;
S32 LLVertexBuffer::sCount = 0;
S32 LLVertexBuffer::sGLCount = 0;
S32 LLVertexBuffer::sMappedCount = 0;
Xiaohong Bao
committed
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;
BOOL LLVertexBuffer::sMapped = FALSE;
BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
BOOL LLVertexBuffer::sPreferStreamDraw = FALSE;
std::vector<U32> LLVertexBuffer::sDeleteList;
David Parks
committed
const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms
class LLGLSyncFence : public LLGLFence
{
public:
David Parks
committed
GLsync mSync;
David Parks
committed
LLGLSyncFence()
{
David Parks
committed
mSync = 0;
David Parks
committed
}
~LLGLSyncFence()
{
David Parks
committed
#ifdef GL_ARB_sync
David Parks
committed
if (mSync)
{
glDeleteSync(mSync);
}
David Parks
committed
#endif
David Parks
committed
}
void placeFence()
{
David Parks
committed
#ifdef GL_ARB_sync
David Parks
committed
if (mSync)
{
glDeleteSync(mSync);
}
mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
David Parks
committed
#endif
David Parks
committed
}
void wait()
{
David Parks
committed
#ifdef GL_ARB_sync
David Parks
committed
if (mSync)
{
while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
{ //track the number of times we've waited here
static S32 waits = 0;
waits++;
}
}
David Parks
committed
}
};
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,
sizeof(U8), // TYPE_EMISSIVE
sizeof(F32), // TYPE_WEIGHT,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
};
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,
void LLVertexBuffer::setupClientArrays(U32 data_mask, U32& ref_mask)
{
llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl;
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (ref_mask != data_mask)
llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
U32 mask[] =
{
MAP_VERTEX,
MAP_NORMAL,
MAP_TEXCOORD0,
MAP_COLOR,
MAP_EMISSIVE,
MAP_WEIGHT,
MAP_WEIGHT4,
MAP_BINORMAL,
MAP_CLOTHWEIGHT,
U32 type[] =
{
TYPE_VERTEX,
TYPE_NORMAL,
TYPE_TEXCOORD0,
TYPE_COLOR,
TYPE_EMISSIVE,
TYPE_WEIGHT,
TYPE_WEIGHT4,
TYPE_BINORMAL,
TYPE_CLOTHWEIGHT,
};
GLenum array[] =
{
GL_VERTEX_ARRAY,
GL_NORMAL_ARRAY,
GL_TEXTURE_COORD_ARRAY,
GL_COLOR_ARRAY,
0,
0,
0,
BOOL error = FALSE;
for (U32 i = 0; i < 9; ++i)
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(type[i]);
}
if (ref_mask & mask[i])
if (!(data_mask & mask[i]))
if (loc >= 0)
{
glDisableVertexAttribArrayARB(loc);
}
else if (!shader)
{
glDisableClientState(array[i]);
}
else if (gDebugGL && !shader && array[i])
{ //needs to be enabled, make sure it was (DEBUG)
if (loc < 0 && !glIsEnabled(array[i]))
if (gDebugSession)
{
error = TRUE;
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])
if (loc >= 0)
{
glEnableVertexAttribArrayARB(loc);
}
else if (!shader)
{
glEnableClientState(array[i]);
}
else if (!shader && array[i] && gDebugGL && glIsEnabled(array[i]))
{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
if (gDebugSession)
{
error = TRUE;
gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
}
else
{
llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
}
if (error)
{
ll_fail("LLVertexBuffer::setupClientArrays failed");
}
U32 map_tc[] =
MAP_TEXCOORD1,
MAP_TEXCOORD2,
MAP_TEXCOORD3
};
U32 type_tc[] =
{
TYPE_TEXCOORD1,
TYPE_TEXCOORD2,
TYPE_TEXCOORD3
};
for (U32 i = 0; i < 3; i++)
{
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(type_tc[i]);
}
if (ref_mask & map_tc[i])
if (!(data_mask & map_tc[i]))
{ //disable
if (loc >= 0)
{
glDisableVertexAttribArrayARB(loc);
}
else if (!shader)
{
glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
}
else if (data_mask & map_tc[i])
{
if (loc >= 0)
{
glEnableVertexAttribArrayARB(loc);
}
else if (!shader)
{
glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
}
if (!shader)
if (ref_mask & MAP_BINORMAL)
if (!(data_mask & MAP_BINORMAL))
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
else if (data_mask & MAP_BINORMAL)
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
ref_mask = data_mask;
//static
void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
David Parks
committed
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
gGL.syncMatrices();
David Parks
committed
Xiaohong Bao
committed
llassert_always(norm.size() >= pos.size());
llassert_always(count > 0) ;
unbind();
setupClientArrays(MAP_VERTEX | MAP_NORMAL);
David Parks
committed
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (shader)
{
S32 loc = shader->getAttribLocation(LLVertexBuffer::TYPE_VERTEX);
if (loc > -1)
{
glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
}
loc = shader->getAttribLocation(LLVertexBuffer::TYPE_NORMAL);
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);
}
glDrawArrays(sGLMode[mode], 0, count);
}
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
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
U32 mask = LLVertexBuffer::MAP_VERTEX;
if (tc)
{
mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
}
unbind();
setupClientArrays(mask);
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (shader)
{
S32 loc = shader->getAttribLocation(LLVertexBuffer::TYPE_VERTEX);
if (loc > -1)
{
glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
if (tc)
{
loc = shader->getAttribLocation(LLVertexBuffer::TYPE_TEXCOORD0);
if (loc > -1)
{
glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
}
}
}
}
else
{
glTexCoordPointer(2, GL_FLOAT, 0, tc);
glVertexPointer(3, GL_FLOAT, 16, pos);
}
glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
}
void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
{
if (start >= (U32) mRequestedNumVerts ||
llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mRequestedNumVerts << llendl;
if (indices_offset >= (U32) mRequestedNumIndices ||
{
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;
}
}
}
}
void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
{
validateRange(start, end, count, indices_offset);
gGL.syncMatrices();
David Parks
committed
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
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();
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
David Parks
committed
placeFence();
}
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
David Parks
committed
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
gGL.syncMatrices();
if (indices_offset >= (U32) mRequestedNumIndices ||
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
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();
glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
((U16*) getIndicesPointer()) + indices_offset);
stop_glerror();
David Parks
committed
placeFence();
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{
David Parks
committed
llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
gGL.syncMatrices();
{
llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
}
if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
{
llerrs << "Wrong vertex buffer bound." << llendl;
}
{
llerrs << "Invalid draw mode: " << mode << llendl;
stop_glerror();
glDrawArrays(sGLMode[mode], first, count);
David Parks
committed
placeFence();
Xiaohong Bao
committed
void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ;
if(sEnableVBOs)
{
Merov Linden
committed
//llassert_always(glBindBufferARB) ; //double check the extention for VBO is loaded.
llinfos << "VBO is enabled." << llendl ;
}
else
{
llinfos << "VBO is disabled." << llendl ;
}
Xiaohong Bao
committed
sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;
if(!sPrivatePoolp)
{
sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ;
}
}
//static
void LLVertexBuffer::unbind()
{
if (sGLRenderArray)
{
glBindVertexArray(0);
sGLRenderArray = 0;
}
if (sVBOActive)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
sVBOActive = FALSE;
}
if (sIBOActive)
{
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
sIBOActive = FALSE;
}
sGLRenderBuffer = 0;
sGLRenderIndices = 0;
}
//static
void LLVertexBuffer::cleanupClass()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
if(sPrivatePoolp)
{
LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
sPrivatePoolp = NULL ;
}
Josh Bell
committed
void LLVertexBuffer::clientCopy(F64 max_time)
{
if (!sDeleteList.empty())
{
glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0]));
sDeleteList.clear();
}
}
//----------------------------------------------------------------------------
LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
LLRefCount(),
mNumVerts(0),
mNumIndices(0),
mRequestedNumVerts(-1),
mRequestedNumIndices(-1),
mUsage(usage),
mGLBuffer(0),
mGLArray(0),
mLastMask(0),
Xiaohong Bao
committed
mMappedIndexData(NULL),
mVertexLocked(FALSE),
mIndexLocked(FALSE),
Josh Bell
committed
mFinal(FALSE),
mFilthy(FALSE),
mEmpty(TRUE),
mResized(FALSE),
David Parks
committed
mDynamicSize(FALSE),
mFence(NULL)
LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
David Parks
committed
mFence = NULL;
if (!sEnableVBOs)
{
mUsage = 0 ;
if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
{
mUsage = 0;
}
if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
mUsage = GL_STREAM_DRAW_ARB;
if (mUsage == 0 && LLRender::sGLCoreProfile)
{ //MUST use VBOs for all rendering
mUsage = GL_STREAM_DRAW_ARB;
}
//zero out offsets
for (U32 i = 0; i < TYPE_MAX; i++)
{
mOffsets[i] = 0;
}
//initialize cached attrib pointers
for (U32 i = 0; i < LL_MAX_VERTEX_ATTRIB_LOCATION; i++)
{
mLastPointer[i] = (void*) 0xFFFFFFFF;
}
mTypeMask = typemask;
mSize = 0;
sCount++;
}
//static
S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
{
for (S32 i=0; i<TYPE_MAX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
{
if (offsets)
{
offset += LLVertexBuffer::sTypeSize[i]*num_vertices;
}
//static
S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
{
S32 size = 0;
for (S32 i = 0; i < TYPE_MAX; i++)
{
U32 mask = 1<<i;
if (typemask & mask)
{
size += LLVertexBuffer::sTypeSize[i];
return size;
{
return mSize;
}
// protected, use unref()
//virtual
LLVertexBuffer::~LLVertexBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
destroyGLBuffer();
destroyGLIndices();
if (mGLArray)
{
glDeleteVertexArrays(1, &mGLArray);
}
Xiaohong Bao
committed
David Parks
committed
if (mFence)
{
delete mFence;
}
mFence = NULL;
Xiaohong Bao
committed
llassert_always(!mMappedData && !mMappedIndexData) ;
David Parks
committed
void LLVertexBuffer::placeFence() const
{
/*if (!mFence && useVBOs())
{
if (gGLManager.mHasSync)
{
mFence = new LLGLSyncFence();
}
}
if (mFence)
{
mFence->placeFence();
}*/
}
void LLVertexBuffer::waitFence() const
{
/*if (mFence)
{
mFence->wait();
}*/
}
//----------------------------------------------------------------------------
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
void LLVertexBuffer::genBuffer()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
mGLBuffer = sStreamVBOPool.allocate();
}
else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
mGLBuffer = sDynamicVBOPool.allocate();
}
else
{
BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
glGenBuffersARB(1, (GLuint*)&mGLBuffer);
}
sGLCount++;
}
void LLVertexBuffer::genIndices()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
mGLIndices = sStreamIBOPool.allocate();
}
else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
mGLIndices = sDynamicIBOPool.allocate();
}
else
{
BOOST_STATIC_ASSERT(sizeof(mGLBuffer) == sizeof(GLuint));
glGenBuffersARB(1, (GLuint*)&mGLIndices);
}
sGLCount++;
}
void LLVertexBuffer::releaseBuffer()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
sStreamVBOPool.release(mGLBuffer);
}
else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
sDynamicVBOPool.release(mGLBuffer);
}
else
{
sDeleteList.push_back(mGLBuffer);
}
sGLCount--;
}
void LLVertexBuffer::releaseIndices()
{
if (mUsage == GL_STREAM_DRAW_ARB)
{
sStreamIBOPool.release(mGLIndices);
}
else if (mUsage == GL_DYNAMIC_DRAW_ARB)
{
sDynamicIBOPool.release(mGLIndices);
}
else
{
sDeleteList.push_back(mGLIndices);
}
sGLCount--;
}
void LLVertexBuffer::createGLBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES);
U32 size = getSize();
if (mGLBuffer)
{
destroyGLBuffer();
}
if (size == 0)
{
return;
}
mEmpty = TRUE;
if (useVBOs())
{
mMappedData = NULL;
genBuffer();
mResized = TRUE;
}
else
{
static int gl_buffer_idx = 0;
mGLBuffer = ++gl_buffer_idx;
mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
}
}
void LLVertexBuffer::createGLIndices()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES);
U32 size = getIndicesSize();
if (mGLIndices)
{
destroyGLIndices();
}
if (size == 0)
{
return;
}
mEmpty = TRUE;
//pad by 16 bytes for aligned copies
size += 16;
//pad by another 16 bytes for VBO pointer adjustment
size += 16;
mMappedIndexData = NULL;
genIndices();
mResized = TRUE;
}
else
{
mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
static int gl_buffer_idx = 0;
mGLIndices = ++gl_buffer_idx;
}
}
void LLVertexBuffer::destroyGLBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER);
if (mGLBuffer)
{
if (useVBOs())
{
Xiaohong Bao
committed
freeClientBuffer() ;
if (mMappedData || mMappedIndexData)
{
llerrs << "Vertex buffer destroyed while mapped!" << llendl;
}
releaseBuffer();
}
else
{
FREE_MEM(sPrivatePoolp, mMappedData) ;
mMappedData = NULL;
mEmpty = TRUE;
sAllocatedBytes -= getSize();
}
mGLBuffer = 0;
//unbind();
}
void LLVertexBuffer::destroyGLIndices()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES);
if (mGLIndices)
{
if (useVBOs())
{
Xiaohong Bao
committed
freeClientBuffer() ;
if (mMappedData || mMappedIndexData)
{
llerrs << "Vertex buffer destroyed while mapped." << llendl;
}
Loren Shih
committed
releaseIndices();
}
else
{
FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
mMappedIndexData = NULL;
mEmpty = TRUE;
sAllocatedBytes -= getIndicesSize();
}
mGLIndices = 0;
//unbind();
}
void LLVertexBuffer::updateNumVerts(S32 nverts)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS);
if (nverts >= 65535)
{
llwarns << "Vertex buffer overflow!" << llendl;
nverts = 65535;
}
mRequestedNumVerts = nverts;
if (!mDynamicSize)
{
mNumVerts = nverts;
}
else if (mUsage == GL_STATIC_DRAW_ARB ||
nverts > mNumVerts ||
nverts < mNumVerts/2)
{
if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535)
{
nverts += nverts/4;
}
mNumVerts = nverts;
}
mSize = calcOffsets(mTypeMask, mOffsets, mNumVerts);
}
void LLVertexBuffer::updateNumIndices(S32 nindices)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES);
mRequestedNumIndices = nindices;
if (!mDynamicSize)
{
mNumIndices = nindices;
}
else if (mUsage == GL_STATIC_DRAW_ARB ||
nindices > mNumIndices ||
nindices < mNumIndices/2)
{
if (mUsage != GL_STATIC_DRAW_ARB)
{
nindices += nindices/4;
}
mNumIndices = nindices;
}
}
void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
if (nverts < 0 || nindices < 0 ||
nverts > 65536)
{
llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl;
}
updateNumVerts(nverts);
updateNumIndices(nindices);
if (mMappedData)
{
llerrs << "LLVertexBuffer::allocateBuffer() called redundantly." << llendl;
}
if (create && (nverts || nindices))
{
createGLBuffer();
createGLIndices();
if (gGLManager.mHasVertexArrayObject && useVBOs() && LLRender::sGLCoreProfile)
{
glGenVertexArrays(1, &mGLArray);
}
}
sAllocatedBytes += getSize() + getIndicesSize();
}
void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
mRequestedNumVerts = newnverts;
mRequestedNumIndices = newnindices;
LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
mDynamicSize = TRUE;
if (mUsage == GL_STATIC_DRAW_ARB)
{ //always delete/allocate static buffers on resize
destroyGLBuffer();
destroyGLIndices();
allocateBuffer(newnverts, newnindices, TRUE);
mFinal = FALSE;
}
else if (newnverts > mNumVerts || newnindices > mNumIndices ||
newnverts < mNumVerts/2 || newnindices < mNumIndices/2)
{
sAllocatedBytes -= getSize() + getIndicesSize();
updateNumVerts(newnverts);
updateNumIndices(newnindices);
S32 newsize = getSize();
S32 new_index_size = getIndicesSize();
sAllocatedBytes += newsize + new_index_size;
if (newsize)
{
if (!mGLBuffer)
{ //no buffer exists, create a new one
createGLBuffer();
}
else
{
if (!useVBOs())
{
mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, newsize);
}
mResized = TRUE;
}
}
else if (mGLBuffer)
{
destroyGLBuffer();
}
if (new_index_size)
{
if (!mGLIndices)
{
createGLIndices();
}
else
{
if (!useVBOs())
{
FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, new_index_size);
}
mResized = TRUE;
}
}
else if (mGLIndices)
{
destroyGLIndices();
}
}
if (mResized && useVBOs())
{
Xiaohong Bao
committed
freeClientBuffer() ;
setBuffer(0);
}
}
BOOL LLVertexBuffer::useVBOs() const
{
//it's generally ineffective to use VBO for things that are streaming on apple
if (!mUsage)
{
return FALSE;
}
David Parks
committed
}
//----------------------------------------------------------------------------
Xiaohong Bao
committed
void LLVertexBuffer::freeClientBuffer()
{
if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData))
{
FREE_MEM(sPrivatePoolp, mMappedData) ;
FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
Xiaohong Bao
committed
mMappedData = NULL ;
mMappedIndexData = NULL ;
}
}
Xiaohong Bao
committed
void LLVertexBuffer::allocateClientVertexBuffer()
Xiaohong Bao
committed
{
if(!mMappedData)
{
mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getSize());
Xiaohong Bao
committed
}
Xiaohong Bao
committed
}
Xiaohong Bao
committed
Xiaohong Bao
committed
void LLVertexBuffer::allocateClientIndexBuffer()
{
Xiaohong Bao
committed
if(!mMappedIndexData)
{
mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getIndicesSize());
Xiaohong Bao
committed
}
}
bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
{
S32 end = index+count;
S32 region_end = region.mIndex+region.mCount;
if (end < region.mIndex ||
index > region_end)
{ //gap exists, do not merge
return false;
}
S32 new_end = llmax(end, region_end);
S32 new_index = llmin(index, region.mIndex);
region.mIndex = new_index;
region.mCount = new_end-new_index;
return true;
}
// Map for data access
U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
Xiaohong Bao
committed
llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl;
if (!useVBOs() && !mMappedData && !mMappedIndexData)
Xiaohong Bao
committed
llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl;
if (useVBOs())
if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (count == -1)
{
David Parks
committed
count = mNumVerts-index;
}
bool mapped = false;
//see if range is already mapped
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
MappedRegion& region = mMappedVertexRegions[i];
if (region.mType == type)
{
if (expand_region(region, index, count))
{
mapped = true;
David Parks
committed
break;
}
}
}
if (!mapped)
{
//not already mapped, map new region
David Parks
committed
MappedRegion region(type, !sDisableVBOMapping && map_range ? -1 : index, count);
mMappedVertexRegions.push_back(region);
}
}
if (mVertexLocked && map_range)
{
llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl;
}
if (!mVertexLocked)
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
Xiaohong Bao
committed
setBuffer(0, type);
mVertexLocked = TRUE;
David Parks
committed
sMappedCount++;
stop_glerror();
Xiaohong Bao
committed
if(sDisableVBOMapping)
{
map_range = false;
Xiaohong Bao
committed
allocateClientVertexBuffer() ;
}
else
{
U8* src = NULL;
David Parks
committed
waitFence();
if (gGLManager.mHasMapBufferRange)
{
if (map_range)
{
S32 offset = mOffsets[type] + sTypeSize[type]*index;
S32 length = (sTypeSize[type]*count+0xF) & ~0xF;
David Parks
committed
src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length,
GL_MAP_WRITE_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT |
GL_MAP_INVALIDATE_RANGE_BIT);
}
else
{
David Parks
committed
src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize,
GL_MAP_WRITE_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT);
#endif
}
}
else if (gGLManager.mHasFlushBufferRange)
{
if (map_range)
{
glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
else
{
src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
}
else
{
map_range = false;
src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
mAlignedOffset = mMappedData - src;
Loren Shih
committed
Xiaohong Bao
committed
}
if (!mMappedData)
{
log_glerror();
//check the availability of memory
LLMemory::logMemoryInfo(TRUE) ;
if(!sDisableVBOMapping)
{
//--------------------
//print out more debug info before crash
llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ;
GLint size ;
glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ;
llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ;
//--------------------
GLint buff;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
if ((GLuint)buff != mGLBuffer)
{
llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
}
llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
}
else
Xiaohong Bao
committed
{
llerrs << "memory allocation for vertex data failed." << llendl ;
Xiaohong Bao
committed
}
}
else
{
map_range = false;
Xiaohong Bao
committed
}
if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping)
{
return mMappedData;
}
else
{
return mMappedData+mOffsets[type]+sTypeSize[type]*index;
}
Xiaohong Bao
committed
}
U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
Xiaohong Bao
committed
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
if (mFinal)
{
llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl;
}
if (!useVBOs() && !mMappedData && !mMappedIndexData)
{
llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl;
}
if (useVBOs())
Xiaohong Bao
committed
{
if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (count == -1)
{
David Parks
committed
count = mNumIndices-index;
}
bool mapped = false;
//see if range is already mapped
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
MappedRegion& region = mMappedIndexRegions[i];
if (expand_region(region, index, count))
{
mapped = true;
David Parks
committed
break;
}
}
if (!mapped)
{
//not already mapped, map new region
David Parks
committed
MappedRegion region(TYPE_INDEX, !sDisableVBOMapping && map_range ? -1 : index, count);
mMappedIndexRegions.push_back(region);
}
}
if (mIndexLocked && map_range)
{
llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl;
}
if (!mIndexLocked)
Xiaohong Bao
committed
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
setBuffer(0, TYPE_INDEX);
mIndexLocked = TRUE;
David Parks
committed
sMappedCount++;
Xiaohong Bao
committed
stop_glerror();
if(sDisableVBOMapping)
{
map_range = false;
Xiaohong Bao
committed
allocateClientIndexBuffer() ;
}
else
{
U8* src = NULL;
David Parks
committed
waitFence();
if (gGLManager.mHasMapBufferRange)
{
if (map_range)
{
S32 offset = sizeof(U16)*index;
S32 length = sizeof(U16)*count;
David Parks
committed
src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length,
GL_MAP_WRITE_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT |
GL_MAP_INVALIDATE_RANGE_BIT);
}
else
{
David Parks
committed
src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices,
GL_MAP_WRITE_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT);
#endif
}
}
else if (gGLManager.mHasFlushBufferRange)
{
if (map_range)
{
glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
else
{
src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
}
else
{
map_range = false;
src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src);
mAlignedIndexOffset = mMappedIndexData - src;
stop_glerror();
Xiaohong Bao
committed
}
}
if (!mMappedIndexData)
{
log_glerror();
Xiaohong Bao
committed
if(!sDisableVBOMapping)
Xiaohong Bao
committed
GLint buff;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
if ((GLuint)buff != mGLIndices)
{
llerrs << "Invalid GL index buffer bound: " << buff << llendl;
}
Xiaohong Bao
committed
llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
}
else
{
llerrs << "memory allocation for Index data failed. " << llendl ;
}
else
{
map_range = false;
}
Xiaohong Bao
committed
if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping)
{
return mMappedIndexData;
}
else
{
return mMappedIndexData + sizeof(U16)*index;
}
Xiaohong Bao
committed
void LLVertexBuffer::unmapBuffer(S32 type)
LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
if (!useVBOs() || type == -2)
Xiaohong Bao
committed
{
return ; //nothing to unmap
}
bool updated_all = false ;
Xiaohong Bao
committed
if (mMappedData && mVertexLocked && type != TYPE_INDEX)
Xiaohong Bao
committed
updated_all = (mIndexLocked && type < 0) ; //both vertex and index buffers done updating
if(sDisableVBOMapping)
Xiaohong Bao
committed
{
David Parks
committed
if (!mMappedVertexRegions.empty())
{
stop_glerror();
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
const MappedRegion& region = mMappedVertexRegions[i];
S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
S32 length = sTypeSize[region.mType]*region.mCount;
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, mMappedData+offset);
stop_glerror();
}
mMappedVertexRegions.clear();
}
else
{
stop_glerror();
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData);
stop_glerror();
}
Xiaohong Bao
committed
}
else
{
if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (!mMappedVertexRegions.empty())
{
stop_glerror();
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
const MappedRegion& region = mMappedVertexRegions[i];
S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
S32 length = sTypeSize[region.mType]*region.mCount;
if (gGLManager.mHasMapBufferRange)
{
#ifdef GL_ARB_map_buffer_range
glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
#endif
}
else if (gGLManager.mHasFlushBufferRange)
{
glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
}
stop_glerror();
}
mMappedVertexRegions.clear();
}
}
Xiaohong Bao
committed
stop_glerror();
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
stop_glerror();
Xiaohong Bao
committed
mMappedData = NULL;
}
Xiaohong Bao
committed
mVertexLocked = FALSE ;
sMappedCount--;
}
if (mMappedIndexData && mIndexLocked && (type < 0 || type == TYPE_INDEX))
Xiaohong Bao
committed
{
if(sDisableVBOMapping)
{
David Parks
committed
if (!mMappedIndexRegions.empty())
{
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
const MappedRegion& region = mMappedIndexRegions[i];
S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
S32 length = sizeof(U16)*region.mCount;
glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, mMappedIndexData+offset);
stop_glerror();
}
mMappedIndexRegions.clear();
}
else
{
stop_glerror();
glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData);
stop_glerror();
}
Xiaohong Bao
committed
}
else
{
if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
{
if (!mMappedIndexRegions.empty())
{
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
const MappedRegion& region = mMappedIndexRegions[i];
S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
S32 length = sizeof(U16)*region.mCount;
if (gGLManager.mHasMapBufferRange)
{
#ifdef GL_ARB_map_buffer_range
glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
#endif
}
else if (gGLManager.mHasFlushBufferRange)
{
David Parks
committed
#ifdef GL_APPLE_flush_buffer_range
glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
David Parks
committed
#endif
stop_glerror();
}
mMappedIndexRegions.clear();
}
}
Xiaohong Bao
committed
stop_glerror();
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
stop_glerror();
Xiaohong Bao
committed
mMappedIndexData = NULL ;
}
mIndexLocked = FALSE ;
sMappedCount--;
}
if(updated_all)
{
if(mUsage == GL_STATIC_DRAW_ARB)
{
//static draw buffers can only be mapped a single time
//throw out client data (we won't be using it again)
mEmpty = TRUE;
mFinal = TRUE;
if(sDisableVBOMapping)
Xiaohong Bao
committed
{
Xiaohong Bao
committed
freeClientBuffer() ;
Xiaohong Bao
committed
}
Xiaohong Bao
committed
}
else
{
mEmpty = FALSE;
}
}
}
//----------------------------------------------------------------------------
template <class T,S32 type> struct VertexBufferStrider
{
typedef LLStrider<T> strider_t;
static bool get(LLVertexBuffer& vbo,
strider_t& strider,
S32 index, S32 count, bool map_range)
{
if (type == LLVertexBuffer::TYPE_INDEX)
{
U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
if (ptr == NULL)
Xiaohong Bao
committed
{
llwarns << "mapIndexBuffer failed!" << llendl;
return FALSE;
}
strider = (T*)ptr;
strider.setStride(0);
return TRUE;
}
else if (vbo.hasDataType(type))
{
S32 stride = LLVertexBuffer::sTypeSize[type];
Xiaohong Bao
committed
U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
if (ptr == NULL)
Xiaohong Bao
committed
{
llwarns << "mapVertexBuffer failed!" << llendl;
return FALSE;
}
strider = (T*)ptr;
strider.setStride(stride);
return TRUE;
}
else
{
llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
}
return FALSE;
}
};
bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getEmissiveStrider(LLStrider<U8>& strider, S32 index, S32 count, bool map_range)
{
return VertexBufferStrider<U8,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range);
}
bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range);
bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range);
}
//----------------------------------------------------------------------------
// Set for rendering
Xiaohong Bao
committed
void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
//set up pointers if the data mask is different ...
U32& ref_mask = mGLArray ? mLastMask : sLastMask;
BOOL setup = (ref_mask != data_mask);
David Parks
committed
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
if (gDebugGL && data_mask != 0)
{
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (shader)
{
U32 required_mask = 0;
for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i)
{
if (shader->getAttribLocation(i) > -1)
{
U32 required = 1 << i;
if ((data_mask & required) == 0)
{
llwarns << "Missing attribute: " << i << llendl;
}
required_mask |= required;
}
}
if ((data_mask & required_mask) != required_mask)
{
llerrs << "Shader consumption mismatches data provision." << llendl;
}
}
}
if (useVBOs())
{
if (mGLArray && mGLArray != sGLRenderArray)
{
glBindVertexArray(mGLArray);
sGLRenderArray = mGLArray;
}
if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
{
/*if (sMapped)
{
llerrs << "VBO bound while another VBO mapped!" << llendl;
}*/
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
sBindCount++;
sVBOActive = TRUE;
setup = TRUE; // ... or the bound buffer changed
}
if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))
{
/*if (sMapped)
{
llerrs << "VBO bound while another VBO mapped!" << llendl;
}*/
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
sBindCount++;
sIBOActive = TRUE;
}
BOOL error = FALSE;
if (gDebugGL)
{
GLint buff;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
if (gDebugSession)
{
error = TRUE;
gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl;
}
else
{
llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
}
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
if ((GLuint)buff != mGLIndices)
if (gDebugSession)
{
error = TRUE;
gFailLog << "Invalid GL index buffer bound: " << buff << std::endl;
}
else
{
llerrs << "Invalid GL index buffer bound: " << buff << llendl;
}
if (mResized)
{
if (gDebugGL)
{
GLint buff;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
if (gDebugSession)
{
error = TRUE;
gFailLog << "Invalid GL vertex buffer bound: " << std::endl;
}
else
{
llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
}
if (mGLIndices != 0)
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
if ((GLuint)buff != mGLIndices)
if (gDebugSession)
{
error = TRUE;
gFailLog << "Invalid GL index buffer bound: "<< std::endl;
}
else
{
llerrs << "Invalid GL index buffer bound: " << buff << llendl;
}
Xiaohong Bao
committed
if (mGLBuffer)
{
glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), NULL, mUsage);
}
Xiaohong Bao
committed
if (mGLIndices)
{
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), NULL, mUsage);
}
mEmpty = TRUE;
mResized = FALSE;
if (data_mask != 0)
{
if (gDebugSession)
{
error = TRUE;
gFailLog << "Buffer set for rendering before being filled after resize." << std::endl;
}
else
{
llerrs << "Buffer set for rendering before being filled after resize." << llendl;
}
}
}
if (error)
{
ll_fail("LLVertexBuffer::mapBuffer failed");
}
Xiaohong Bao
committed
unmapBuffer(type);
Josh Bell
committed
{
if (mGLBuffer)
{
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
sBindCount++;
sVBOActive = FALSE;
setup = TRUE; // ... or a VBO is deactivated
}
if (sGLRenderBuffer != mGLBuffer)
{
setup = TRUE; // ... or a client memory pointer changed
}
}
if (mGLIndices && sIBOActive)
/*if (sMapped)
{
llerrs << "VBO unbound while potentially mapped!" << llendl;
}*/
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
sBindCount++;
sIBOActive = FALSE;
}
}
setupClientArrays(data_mask, ref_mask);
if (mGLIndices)
{
sGLRenderIndices = mGLIndices;
}
if (mGLBuffer)
{
sGLRenderBuffer = mGLBuffer;
if (data_mask && setup)
{
setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
sSetCount++;
}
}
}
// virtual (default)
void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
if ((data_mask & mTypeMask) != data_mask)
{
llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
}
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
//assert that fixed function is allowed OR a shader is currently bound
llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
if (data_mask & MAP_NORMAL)
{
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(TYPE_NORMAL);
}
if (loc >= 0)
{
void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
if (mLastPointer[loc] != ptr)
{
glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
}
if (mGLArray)
{
mLastPointer[loc] = ptr;
}
}
else if (!shader)
{
glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
}
if (data_mask & MAP_TEXCOORD3)
{
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(TYPE_TEXCOORD3);
}
if (loc >= 0)
{
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
if (mLastPointer[loc] != ptr)
{
glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
}
if (mGLArray)
{
mLastPointer[loc] = ptr;
}
}
else if (!shader)
{
glClientActiveTextureARB(GL_TEXTURE3_ARB);
glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_TEXCOORD2)
{
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(TYPE_TEXCOORD2);
}
if (loc >= 0)
{
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
if (mLastPointer[loc] != ptr)
{
glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
}
if (mGLArray)
{
mLastPointer[loc] = ptr;
}
}
else if (!shader)
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_TEXCOORD1)
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(TYPE_TEXCOORD1);
}
if (loc >= 0)
{
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
if (mLastPointer[loc] != ptr)
{
glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
}
if (mGLArray)
{
mLastPointer[loc] = ptr;
}
}
else if (!shader)
{
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_BINORMAL)
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(TYPE_BINORMAL);
}
if (loc >= 0)
{
void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
if (mLastPointer[loc] != ptr)
{
glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
}
if (mGLArray)
{
mLastPointer[loc] = ptr;
}
}
else if (!shader)
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_TEXCOORD0)
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(TYPE_TEXCOORD0);
}
if (loc >= 0)
{
void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
if (mLastPointer[loc] != ptr)
{
glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
}
if (mGLArray)
{
mLastPointer[loc] = ptr;
}
}
else if (!shader)
{
glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
}
if (data_mask & MAP_COLOR)
{
S32 loc = -1;
if (shader)
{
loc = shader->getAttribLocation(TYPE_COLOR);
}
if (loc >= 0)
{
void* ptr = (void*)(base + mOffsets[TYPE_COLOR]);
if (mLastPointer[loc] != ptr)
{
glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
}
if (mGLArray)
{
Loading
Loading full blame...